Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for "ambiguous associated type" issue with ATBs #61919

Merged
merged 8 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2234,7 +2234,7 @@ pub enum UseKind {
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
pub struct TraitRef {
pub path: P<Path>,
// Don't hash the ref_id. It is tracked via the thing it is used to access
// Don't hash the `ref_id`. It is tracked via the thing it is used to access.
#[stable_hasher(ignore)]
pub hir_ref_id: HirId,
}
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ pub struct Generics {
pub parent_count: usize,
pub params: Vec<GenericParamDef>,

/// Reverse map to the `index` field of each `GenericParamDef`
/// Reverse map to the `index` field of each `GenericParamDef`.
#[stable_hasher(ignore)]
pub param_def_id_to_index: FxHashMap<DefId, u32>,

Expand Down Expand Up @@ -1252,7 +1252,7 @@ impl<'tcx> TraitPredicate<'tcx> {

impl<'tcx> PolyTraitPredicate<'tcx> {
pub fn def_id(&self) -> DefId {
// Ok to skip binder since trait def-ID does not care about regions.
// Ok to skip binder since trait `DefId` does not care about regions.
self.skip_binder().def_id()
}
}
Expand Down Expand Up @@ -1319,7 +1319,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
/// Note that this is not the `DefId` of the `TraitRef` containing this
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
pub fn projection_def_id(&self) -> DefId {
// Ok to skip binder since trait def-ID does not care about regions.
// Ok to skip binder since trait `DefId` does not care about regions.
self.skip_binder().projection_ty.item_def_id
}
}
Expand Down Expand Up @@ -1646,9 +1646,9 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
/// particular point.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
pub struct ParamEnv<'tcx> {
/// Obligations that the caller must satisfy. This is basically
/// `Obligation`s that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
/// into Obligations, and elaborated and normalized.
/// into `Obligation`s, and elaborated and normalized.
pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>,

/// Typically, this is `Reveal::UserFacing`, but during codegen we
Expand Down Expand Up @@ -2796,7 +2796,7 @@ impl<'tcx> TyCtxt<'tcx> {
_ => false,
}
} else {
match self.def_kind(def_id).expect("no def for def-id") {
match self.def_kind(def_id).expect("no def for `DefId`") {
DefKind::AssocConst
| DefKind::Method
| DefKind::AssocTy => true,
Expand Down
13 changes: 7 additions & 6 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
///
/// A Rust trait object type consists (in addition to a lifetime bound)
/// of a set of trait bounds, which are separated into any number
/// of auto-trait bounds, and at most 1 non-auto-trait bound. The
/// of auto-trait bounds, and at most one non-auto-trait bound. The
/// non-auto-trait bound is called the "principal" of the trait
/// object.
///
Expand Down Expand Up @@ -680,7 +680,8 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {

#[inline]
pub fn projection_bounds<'a>(&'a self) ->
impl Iterator<Item=ExistentialProjection<'tcx>> + 'a {
impl Iterator<Item = ExistentialProjection<'tcx>> + 'a
{
self.iter().filter_map(|predicate| {
match *predicate {
ExistentialPredicate::Projection(p) => Some(p),
Expand All @@ -690,7 +691,7 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
}

#[inline]
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
self.iter().filter_map(|predicate| {
match *predicate {
ExistentialPredicate::AutoTrait(d) => Some(d),
Expand All @@ -711,17 +712,17 @@ impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {

#[inline]
pub fn projection_bounds<'a>(&'a self) ->
impl Iterator<Item=PolyExistentialProjection<'tcx>> + 'a {
impl Iterator<Item = PolyExistentialProjection<'tcx>> + 'a {
self.skip_binder().projection_bounds().map(Binder::bind)
}

#[inline]
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
self.skip_binder().auto_traits()
}

pub fn iter<'a>(&'a self)
-> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx {
-> impl DoubleEndedIterator<Item = Binder<ExistentialPredicate<'tcx>>> + 'tcx {
self.skip_binder().iter().cloned().map(Binder::bind)
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/librustc_codegen_llvm/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,11 +450,11 @@ fn subroutine_type_metadata(
false);
}

// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill-
// defined concept. For the case of an actual trait pointer (i.e., Box<Trait>,
// &Trait), trait_object_type should be the whole thing (e.g, Box<Trait>) and
// trait_type should be the actual trait (e.g., Trait). Where the trait is part
// of a DST struct, there is no trait_object_type and the results of this
// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
// of a DST struct, there is no `trait_object_type` and the results of this
// function will be a little bit weird.
fn trait_pointer_metadata(
cx: &CodegenCx<'ll, 'tcx>,
Expand All @@ -464,13 +464,13 @@ fn trait_pointer_metadata(
) -> &'ll DIType {
// The implementation provided here is a stub. It makes sure that the trait
// type is assigned the correct name, size, namespace, and source location.
// But it does not describe the trait's methods.
// However, it does not describe the trait's methods.

let containing_scope = match trait_type.sty {
ty::Dynamic(ref data, ..) =>
data.principal_def_id().map(|did| get_namespace_for_item(cx, did)),
_ => {
bug!("debuginfo: Unexpected trait-object type in \
bug!("debuginfo: unexpected trait-object type in \
trait_pointer_metadata(): {:?}",
trait_type);
}
Expand Down
15 changes: 10 additions & 5 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,14 +1050,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
if !self.in_body {
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
// The traits' privacy in bodies is already checked as a part of trait object types.
let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
if self.visit_trait(*principal.skip_binder()) {
return;
let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);

for (trait_predicate, _) in bounds.trait_bounds {
if self.visit_trait(*trait_predicate.skip_binder()) {
return;
}
}

for (poly_predicate, _) in bounds.projection_bounds {
let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty) ||
self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
if self.visit(poly_predicate.skip_binder().ty)
|| self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
{
return;
}
}
Expand Down
95 changes: 57 additions & 38 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,17 @@ pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;

/// Returns the set of bounds in scope for the type parameter with
/// the given id.
/// Returns predicates in scope of the form `X: Foo`, where `X` is
/// a type parameter `X` with the given id `def_id`. This is a
/// subset of the full set of predicates.
///
/// This is used for one specific purpose: resolving "short-hand"
/// associated type references like `T::Item`. In principle, we
/// would do that by first getting the full set of predicates in
/// scope and then filtering down to find those that apply to `T`,
/// but this can lead to cycle errors. The problem is that we have
/// to do this resolution *in order to create the predicates in
/// the first place*. Hence, we have this "special pass".
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> &'tcx ty::GenericPredicates<'tcx>;

Expand Down Expand Up @@ -775,11 +784,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// The given trait-ref must actually be a trait.
pub(super) fn instantiate_poly_trait_ref_inner(&self,
trait_ref: &hir::TraitRef,
span: Span,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
) -> Option<Vec<Span>> {
let trait_def_id = trait_ref.trait_def_id();

debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
Expand All @@ -794,6 +803,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));

bounds.trait_bounds.push((poly_trait_ref, span));

let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
// Specify type to assert that error was already reported in `Err` case.
Expand All @@ -804,14 +815,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
binding,
bounds,
speculative,
&mut dup_bindings
&mut dup_bindings,
);
// Okay to ignore `Err` because of `ErrorReported` (see above).
}

debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
trait_ref, bounds, poly_trait_ref);
(poly_trait_ref, potential_assoc_types)
potential_assoc_types
}

/// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
Expand All @@ -836,10 +847,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
pub fn instantiate_poly_trait_ref(&self,
poly_trait_ref: &hir::PolyTraitRef,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false)
bounds: &mut Bounds<'tcx>,
) -> Option<Vec<Span>> {
self.instantiate_poly_trait_ref_inner(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
self_ty,
bounds,
false,
)
}

fn ast_path_to_mono_trait_ref(&self,
Expand Down Expand Up @@ -983,12 +999,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}

for bound in trait_bounds {
let (poly_trait_ref, _) = self.instantiate_poly_trait_ref(
let _ = self.instantiate_poly_trait_ref(
bound,
param_ty,
bounds,
);
bounds.trait_bounds.push((poly_trait_ref, bound.span))
}

bounds.region_bounds.extend(region_bounds
Expand Down Expand Up @@ -1172,11 +1187,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
self.add_bounds(
param_ty,
ast_bounds,
bounds,
);
self.add_bounds(param_ty, ast_bounds, bounds);
}
}
Ok(())
Expand Down Expand Up @@ -1216,25 +1227,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
// FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
// not straightforward due to the borrow checker.
let bound_trait_refs: Vec<_> = trait_bounds
.iter()
.rev()
.map(|trait_bound| {
let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
trait_bound,
dummy_self,
&mut bounds,
);
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
(trait_ref, trait_bound.span)
})
.collect();
for trait_bound in trait_bounds.iter().rev() {
let cur_potential_assoc_types = self.instantiate_poly_trait_ref(
trait_bound,
dummy_self,
&mut bounds,
);
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
}

// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.iter().cloned());
let expanded_traits =
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
Expand Down Expand Up @@ -1276,7 +1281,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types = BTreeSet::default();

let regular_traits_refs = bound_trait_refs
let regular_traits_refs = bounds.trait_bounds
.into_iter()
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()))
.map(|(trait_ref, _)| trait_ref);
Expand Down Expand Up @@ -1491,7 +1496,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
let tcx = self.tcx();

debug!(
"find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})",
ty_param_def_id,
assoc_name,
span,
);

let predicates = &self.get_type_parameter_bounds(span, ty_param_def_id).predicates;

debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);

let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());

// Check that there is exactly one way to find an associated type with the
Expand All @@ -1515,7 +1530,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_name: ast::Ident,
span: Span)
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
where I: Iterator<Item=ty::PolyTraitRef<'tcx>>
where I: Iterator<Item = ty::PolyTraitRef<'tcx>>
{
let bound = match bounds.next() {
Some(bound) => bound,
Expand All @@ -1524,13 +1539,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name)
.span_label(span, format!("associated type `{}` not found", assoc_name))
.emit();
.span_label(span, format!("associated type `{}` not found", assoc_name))
.emit();
return Err(ErrorReported);
}
};

debug!("one_bound_for_assoc_type: bound = {:?}", bound);

if let Some(bound2) = bounds.next() {
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);

let bounds = iter::once(bound).chain(iter::once(bound2)).chain(bounds);
let mut err = struct_span_err!(
self.tcx().sess, span, E0221,
Expand All @@ -1544,7 +1563,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item.kind == ty::AssocKind::Type &&
self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id())
})
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));

if let Some(span) = bound_span {
err.span_label(span, format!("ambiguous `{}` from `{}`",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2030,7 +2030,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
}

fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-> &'tcx ty::GenericPredicates<'tcx>
Expand Down
Loading