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

Do not erase late bound regions when selecting inherent associated types #118118

Merged
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
207 changes: 92 additions & 115 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, Ty, TyCtxt, TypeVisitableExt,
self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_trait_selection::traits::{self, ObligationCtxt};

use std::fmt::Display;
use std::slice;
Expand Down Expand Up @@ -1606,133 +1606,110 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
// when inside of an ADT (#108491) or where clause.
let param_env = tcx.param_env(block.owner);
let cause = ObligationCause::misc(span, block.owner.def_id);

let mut fulfillment_errors = Vec::new();
let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
// Regions are not considered during selection.
let self_ty = self_ty
.fold_with(&mut BoundVarEraser { tcx, universe: infcx.create_next_universe() });

struct BoundVarEraser<'tcx> {
tcx: TyCtxt<'tcx>,
universe: ty::UniverseIndex,
}

// FIXME(non_lifetime_binders): Don't assign the same universe to each placeholder.
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarEraser<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
let mut universes = if self_ty.has_escaping_bound_vars() {
vec![None; self_ty.outer_exclusive_binder().as_usize()]
} else {
vec![]
};

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
// FIXME(@lcnr): This is broken, erasing bound regions
// impacts selection as it results in different types.
if r.is_bound() { self.tcx.lifetimes.re_erased } else { r }
}
let (impl_, (assoc_item, def_scope)) =
crate::traits::project::with_replaced_escaping_bound_vars(
infcx,
&mut universes,
self_ty,
|self_ty| {
self.select_inherent_assoc_type_candidates(
infcx, name, span, self_ty, param_env, candidates,
)
},
)?;

self.check_assoc_ty(assoc_item, name, def_scope, block, span);

// FIXME(fmease): Currently creating throwaway `parent_args` to please
// `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to
// not require the parent args logic.
let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args);
let args = tcx.mk_args_from_iter(
std::iter::once(ty::GenericArg::from(self_ty))
.chain(args.into_iter().skip(parent_args.len())),
);

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Bound(_, bv) => Ty::new_placeholder(
self.tcx,
ty::PlaceholderType { universe: self.universe, bound: bv },
),
_ => ty.super_fold_with(self),
}
}
let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));

fn fold_const(
&mut self,
ct: ty::Const<'tcx>,
) -> <TyCtxt<'tcx> as rustc_type_ir::Interner>::Const {
assert!(!ct.ty().has_escaping_bound_vars());

match ct.kind() {
ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder(
self.tcx,
ty::PlaceholderConst { universe: self.universe, bound: bv },
ct.ty(),
),
_ => ct.super_fold_with(self),
}
}
}
Ok(Some((ty, assoc_item)))
}

let InferOk { value: self_ty, obligations } =
infcx.at(&cause, param_env).normalize(self_ty);
fn select_inherent_assoc_type_candidates(
&self,
infcx: &InferCtxt<'tcx>,
name: Ident,
span: Span,
self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();

candidates
.iter()
.copied()
.filter(|&(impl_, _)| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations.clone());

let impl_args = infcx.fresh_args_for_item(span, impl_);
let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);

// Check that the self types can be related.
if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
return false;
}
let applicable_candidates: Vec<_> = candidates
.iter()
.copied()
.filter(|&(impl_, _)| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new(infcx);
let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);

let impl_args = infcx.fresh_args_for_item(span, impl_);
let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);

// Check that the self types can be related.
if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
return false;
}

// Check whether the impl imposes obligations we have to worry about.
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
let impl_obligations = traits::predicates_for_generics(
|_, _| cause.clone(),
param_env,
impl_bounds,
);
ocx.register_obligations(impl_obligations);
// Check whether the impl imposes obligations we have to worry about.
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
let impl_bounds =
ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
let impl_obligations = traits::predicates_for_generics(
|_, _| ObligationCause::dummy(),
param_env,
impl_bounds,
);
ocx.register_obligations(impl_obligations);

let mut errors = ocx.select_where_possible();
if !errors.is_empty() {
fulfillment_errors.append(&mut errors);
return false;
}
let mut errors = ocx.select_where_possible();
if !errors.is_empty() {
fulfillment_errors.append(&mut errors);
return false;
}

true
})
true
})
.collect()
});
})
.collect();

if applicable_candidates.len() > 1 {
return Err(self.complain_about_ambiguous_inherent_assoc_type(
match &applicable_candidates[..] {
&[] => Err(self.complain_about_inherent_assoc_type_not_found(
name,
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
self_ty,
candidates,
fulfillment_errors,
span,
));
}
)),

if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
self.check_assoc_ty(assoc_item, name, def_scope, block, span);

// FIXME(fmease): Currently creating throwaway `parent_args` to please
// `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to
// not require the parent args logic.
let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args);
let args = tcx.mk_args_from_iter(
std::iter::once(ty::GenericArg::from(self_ty))
.chain(args.into_iter().skip(parent_args.len())),
);

let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));
&[applicable_candidate] => Ok(applicable_candidate),

return Ok(Some((ty, assoc_item)));
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_type(
name,
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
span,
)),
}

Err(self.complain_about_inherent_assoc_type_not_found(
name,
self_ty,
candidates,
fulfillment_errors,
span,
))
}

fn lookup_assoc_ty(
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,18 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(

// Infer the generic parameters of the impl by unifying the
// impl type with the self type of the projection.
let self_ty = alias_ty.self_ty();
let mut self_ty = alias_ty.self_ty();
if !selcx.infcx.next_trait_solver() {
self_ty = normalize_with_depth_to(
selcx,
param_env,
cause.clone(),
depth + 1,
self_ty,
obligations,
);
}

match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
Ok(mut ok) => obligations.append(&mut ok.obligations),
Err(_) => {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/associated-inherent-types/assoc-inherent-late-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// check-pass

#![feature(inherent_associated_types)]
#![allow(incomplete_features)]

struct Foo<T>(T);

impl<'a> Foo<fn(&'a ())> {
type Assoc = &'a ();
}

fn bar(_: for<'a> fn(Foo<fn(Foo<fn(&'static ())>::Assoc)>::Assoc)) {}

fn main() {}
1 change: 1 addition & 0 deletions tests/ui/associated-inherent-types/issue-111404-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ impl<'a> Foo<fn(&'a ())> {

fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
//~^ ERROR higher-ranked subtype error
//~| ERROR higher-ranked subtype error

fn main() {}
10 changes: 9 additions & 1 deletion tests/ui/associated-inherent-types/issue-111404-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,13 @@ error: higher-ranked subtype error
LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error
error: higher-ranked subtype error
--> $DIR/issue-111404-1.rs:10:1
|
LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 2 previous errors