-
Notifications
You must be signed in to change notification settings - Fork 13.4k
iat selection: normalize self ty & completely erase bound vars #112493
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,10 +26,9 @@ 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, TyCtxtInferExt}; | ||
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; | ||
use rustc_infer::traits::ObligationCause; | ||
use rustc_middle::middle::stability::AllowUnstable; | ||
use rustc_middle::ty::fold::FnMutDelegate; | ||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; | ||
use rustc_middle::ty::GenericParamDefKind; | ||
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; | ||
|
@@ -43,7 +42,10 @@ use rustc_trait_selection::traits::error_reporting::{ | |
report_object_safety_error, suggestions::NextTypeParamName, | ||
}; | ||
use rustc_trait_selection::traits::wf::object_region_bounds; | ||
use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt}; | ||
use rustc_trait_selection::traits::{ | ||
self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt, | ||
}; | ||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; | ||
|
||
use smallvec::{smallvec, SmallVec}; | ||
use std::collections::BTreeSet; | ||
|
@@ -2442,6 +2444,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { | |
return Ok(None); | ||
} | ||
|
||
if !tcx.features().inherent_associated_types { | ||
tcx.sess | ||
.delay_span_bug(span, "found inherent assoc type without the feature being gated"); | ||
} | ||
|
||
// | ||
// Select applicable inherent associated type candidates modulo regions. | ||
// | ||
|
@@ -2465,30 +2472,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { | |
|
||
let mut fulfillment_errors = Vec::new(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also kinda unrelated but do you mind, at the top of |
||
let mut applicable_candidates: Vec<_> = infcx.probe(|_| { | ||
let universe = infcx.create_next_universe(); | ||
|
||
// Regions are not considered during selection. | ||
// FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes | ||
// of type and const binders. Is that correct in the selection phase? See also #109505. | ||
let self_ty = tcx.replace_escaping_bound_vars_uncached( | ||
self_ty, | ||
FnMutDelegate { | ||
regions: &mut |_| tcx.lifetimes.re_erased, | ||
types: &mut |bv| { | ||
tcx.mk_placeholder(ty::PlaceholderType { universe, bound: bv }) | ||
}, | ||
consts: &mut |bv, ty| { | ||
tcx.mk_const(ty::PlaceholderConst { universe, bound: bv }, ty) | ||
}, | ||
}, | ||
); | ||
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 | ||
} | ||
|
||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { | ||
if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r } | ||
} | ||
|
||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | ||
match *ty.kind() { | ||
ty::Bound(_, bv) => self.tcx.mk_placeholder(ty::PlaceholderType { | ||
universe: self.universe, | ||
bound: bv, | ||
}), | ||
_ => ty.super_fold_with(self), | ||
} | ||
} | ||
|
||
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) => self.tcx.mk_const( | ||
ty::PlaceholderConst { universe: self.universe, bound: bv }, | ||
ct.ty(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you assert somewhere that the ct ty has no escaping bound vars? |
||
), | ||
_ => ct.super_fold_with(self), | ||
} | ||
} | ||
} | ||
|
||
let InferOk { value: self_ty, obligations } = | ||
infcx.at(&cause, param_env).normalize(self_ty); | ||
|
||
candidates | ||
.iter() | ||
.copied() | ||
.filter(|&(impl_, _)| { | ||
infcx.probe(|_| { | ||
let ocx = ObligationCtxt::new_in_snapshot(&infcx); | ||
ocx.register_obligations(obligations.clone()); | ||
|
||
let impl_substs = infcx.fresh_substs_for_item(span, impl_); | ||
let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs); | ||
|
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(&'a ())>::Assoc)>::Assoc)) {} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#![feature(inherent_associated_types)] | ||
#![allow(incomplete_features)] | ||
|
||
struct Foo<T>(T); | ||
|
||
impl<'a> Foo<fn(&'a ())> { | ||
type Assoc = &'a (); | ||
} | ||
|
||
fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} | ||
//~^ ERROR higher-ranked subtype error | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
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)) {} | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not using
assert!
or similar as we'd ice when sb. defined & used an IAT w/o enabling the feature.Instead of
delay_span_bug
, I could exit early at the very start of the function but that would lead to "spurious" extra errors on IAT use-sites (ambiguous assoc ty) next to the feature gate error.