mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 22:46:50 +00:00
Auto merge of #120991 - matthiaskrgr:rollup-f8kw2st, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #118983 (Warn on references casting to bigger memory layout) - #119451 (Gate PR CI on clippy correctness lints) - #120273 (compiletest: few naive improvements) - #120950 (Fix async closures in CTFE) - #120958 (Dejargonize `subst`) - #120965 (Add lahfsahf and prfchw target feature) - #120970 (add another test for promoteds-in-static) - #120979 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0a5b998c57
@ -691,7 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
|
||||
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
|
||||
// These types seem reasonably opaque enough that they could be substituted with their
|
||||
// These types seem reasonably opaque enough that they could be instantiated with their
|
||||
// borrowed variants in a function body when we see a move error.
|
||||
let borrow_level = match *ty.kind() {
|
||||
ty::Param(_) => tcx
|
||||
@ -3158,7 +3158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// Define a fallback for when we can't match a closure.
|
||||
let fallback = || {
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_like(self.mir_def_id().to_def_id());
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
@ -3369,7 +3369,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id());
|
||||
let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
|
||||
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
|
||||
|
||||
|
@ -67,7 +67,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
local,
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
debug_assert!(is_closure_like(
|
||||
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
@ -126,9 +126,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
item_msg = access_place_desc;
|
||||
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
the_place_err.ty(self.body, self.infcx.tcx).ty
|
||||
));
|
||||
debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty));
|
||||
|
||||
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
|
||||
", as it is a captured variable in a `Fn` closure".to_string()
|
||||
@ -389,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
local,
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
debug_assert!(is_closure_like(
|
||||
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
@ -1474,7 +1472,8 @@ fn suggest_ampmut<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
|
||||
/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
|
||||
fn is_closure_like(ty: Ty<'_>) -> bool {
|
||||
ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// be allowed:
|
||||
/// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
|
||||
///
|
||||
/// Then we map the regions in both the type and the subst to their
|
||||
/// Then we map the regions in both the type and the generic parameters to their
|
||||
/// `external_name` giving `concrete_type = &'a i32`,
|
||||
/// `args = ['static, 'a]`. This will then allow
|
||||
/// `infer_opaque_definition_from_instantiation` to determine that
|
||||
@ -77,9 +77,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let args = opaque_type_key.args;
|
||||
debug!(?concrete_type, ?args);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
let mut arg_regions = vec![self.universal_regions.fr_static];
|
||||
|
||||
let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
|
||||
let to_universal_region = |vid, arg_regions: &mut Vec<_>| {
|
||||
trace!(?vid);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
trace!(?scc);
|
||||
@ -88,11 +88,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}) {
|
||||
Some(region) => {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
arg_regions.push(vid);
|
||||
region
|
||||
}
|
||||
None => {
|
||||
subst_regions.push(vid);
|
||||
arg_regions.push(vid);
|
||||
ty::Region::new_error_with_message(
|
||||
infcx.tcx,
|
||||
concrete_type.span,
|
||||
@ -106,10 +106,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// This will ensure they get precedence when folding the regions in the concrete type.
|
||||
if let Some(&ci) = member_constraints.get(&opaque_type_key) {
|
||||
for &vid in self.member_constraints.choice_regions(ci) {
|
||||
to_universal_region(vid, &mut subst_regions);
|
||||
to_universal_region(vid, &mut arg_regions);
|
||||
}
|
||||
}
|
||||
debug!(?subst_regions);
|
||||
debug!(?arg_regions);
|
||||
|
||||
// Next, insert universal regions from args, so we can translate regions that appear
|
||||
// in them but are not subject to member constraints, for instance closure args.
|
||||
@ -119,18 +119,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
return region;
|
||||
}
|
||||
let vid = self.to_region_vid(region);
|
||||
to_universal_region(vid, &mut subst_regions)
|
||||
to_universal_region(vid, &mut arg_regions)
|
||||
});
|
||||
debug!(?universal_args);
|
||||
debug!(?subst_regions);
|
||||
debug!(?arg_regions);
|
||||
|
||||
// Deduplicate the set of regions while keeping the chosen order.
|
||||
let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
|
||||
debug!(?subst_regions);
|
||||
let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>();
|
||||
debug!(?arg_regions);
|
||||
|
||||
let universal_concrete_type =
|
||||
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
|
||||
ty::ReVar(vid) => subst_regions
|
||||
ty::ReVar(vid) => arg_regions
|
||||
.iter()
|
||||
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
|
||||
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
|
||||
|
@ -29,7 +29,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
|
||||
if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
|
||||
if !self.tcx().is_closure_like(mir_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -479,7 +479,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
||||
// `+multivalue` feature because the purpose of the wasm abi is to match
|
||||
// the WebAssembly specification, which has this feature. This won't be
|
||||
// needed when LLVM enables this `multivalue` feature by default.
|
||||
if !cx.tcx.is_closure_or_coroutine(instance.def_id()) {
|
||||
if !cx.tcx.is_closure_like(instance.def_id()) {
|
||||
let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
|
||||
if abi == Abi::Wasm {
|
||||
function_features.push("+multivalue".to_string());
|
||||
|
@ -213,6 +213,7 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
|
||||
("x86", "rdrand") => LLVMFeature::new("rdrnd"),
|
||||
("x86", "bmi1") => LLVMFeature::new("bmi"),
|
||||
("x86", "cmpxchg16b") => LLVMFeature::new("cx16"),
|
||||
("x86", "lahfsahf") => LLVMFeature::new("sahf"),
|
||||
("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"),
|
||||
("aarch64", "dpb") => LLVMFeature::new("ccpp"),
|
||||
("aarch64", "dpb2") => LLVMFeature::new("ccdp"),
|
||||
|
@ -229,7 +229,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::track_caller => {
|
||||
let is_closure = tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = fn_sig()
|
||||
@ -274,7 +274,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
}
|
||||
}
|
||||
sym::target_feature => {
|
||||
if !tcx.is_closure_or_coroutine(did.to_def_id())
|
||||
if !tcx.is_closure_like(did.to_def_id())
|
||||
&& let Some(fn_sig) = fn_sig()
|
||||
&& fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
|
||||
{
|
||||
@ -529,7 +529,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
// would result in this closure being compiled without the inherited target features, but this
|
||||
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
||||
if tcx.features().target_feature_11
|
||||
&& tcx.is_closure_or_coroutine(did.to_def_id())
|
||||
&& tcx.is_closure_like(did.to_def_id())
|
||||
&& codegen_fn_attrs.inline != InlineAttr::Always
|
||||
{
|
||||
let owner_id = tcx.parent(did.to_def_id());
|
||||
|
@ -77,6 +77,8 @@ pub fn from_target_feature(
|
||||
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
|
||||
Some(sym::csky_target_feature) => rust_features.csky_target_feature,
|
||||
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
|
||||
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
|
||||
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
|
||||
Some(name) => bug!("unknown target feature gate {}", name),
|
||||
None => true,
|
||||
};
|
||||
|
@ -554,18 +554,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
/// Call this on things you got out of the MIR (so it is as generic as the current
|
||||
/// stack frame), to bring it into the proper environment for this interpreter.
|
||||
pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<
|
||||
pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
>(
|
||||
&self,
|
||||
value: T,
|
||||
) -> Result<T, ErrorHandled> {
|
||||
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
|
||||
self.instantiate_from_frame_and_normalize_erasing_regions(self.frame(), value)
|
||||
}
|
||||
|
||||
/// Call this on things you got out of the MIR (so it is as generic as the provided
|
||||
/// stack frame), to bring it into the proper environment for this interpreter.
|
||||
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
>(
|
||||
&self,
|
||||
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
|
||||
value: T,
|
||||
@ -656,7 +658,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
|
||||
let local_ty = frame.body.local_decls[local].ty;
|
||||
let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
|
||||
let local_ty =
|
||||
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
|
||||
self.layout_of(local_ty)
|
||||
})?;
|
||||
|
||||
@ -791,8 +794,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||
if M::POST_MONO_CHECKS {
|
||||
for &const_ in &body.required_consts {
|
||||
let c =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
|
||||
let c = self
|
||||
.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
|
||||
c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| {
|
||||
err.emit_note(*self.tcx);
|
||||
err
|
||||
|
@ -696,9 +696,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
trace!("eval_place_to_op: got {:?}", op);
|
||||
// Sanity-check the type we ended up with.
|
||||
if cfg!(debug_assertions) {
|
||||
let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
)?;
|
||||
let normalized_place_ty = self
|
||||
.instantiate_from_current_frame_and_normalize_erasing_regions(
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
)?;
|
||||
if !mir_assign_valid_types(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
@ -731,8 +732,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
|
||||
|
||||
Constant(constant) => {
|
||||
let c =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
|
||||
let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(
|
||||
constant.const_,
|
||||
)?;
|
||||
|
||||
// This can still fail:
|
||||
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
|
||||
|
@ -542,9 +542,10 @@ where
|
||||
trace!("{:?}", self.dump_place(&place));
|
||||
// Sanity-check the type we ended up with.
|
||||
if cfg!(debug_assertions) {
|
||||
let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
)?;
|
||||
let normalized_place_ty = self
|
||||
.instantiate_from_current_frame_and_normalize_erasing_regions(
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
)?;
|
||||
if !mir_assign_valid_types(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
|
@ -235,7 +235,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
NullaryOp(ref null_op, ty) => {
|
||||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||
let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||
let layout = self.layout_of(ty)?;
|
||||
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
|
||||
&& layout.is_unsized()
|
||||
@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Cast(cast_kind, ref operand, cast_ty) => {
|
||||
let src = self.eval_operand(operand, None)?;
|
||||
let cast_ty =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
|
||||
self.instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
|
||||
self.cast(&src, cast_kind, cast_ty, &dest)?;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Drop { place, target, unwind, replace: _ } => {
|
||||
let frame = self.frame();
|
||||
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
|
||||
let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
|
||||
let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?;
|
||||
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
|
||||
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
|
||||
// This is the branch we enter if and only if the dropped type has no drop glue
|
||||
@ -672,8 +672,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Construct the destination place for this argument. At this point all
|
||||
// locals are still dead, so we cannot construct a `PlaceTy`.
|
||||
let dest = mir::Place::from(local);
|
||||
// `layout_of_local` does more than just the substitution we need to get the
|
||||
// type, but the result gets cached so this avoids calling the substitution
|
||||
// `layout_of_local` does more than just the instantiation we need to get the
|
||||
// type, but the result gets cached so this avoids calling the instantiation
|
||||
// query *again* the next time this local is accessed.
|
||||
let ty = self.layout_of_local(self.frame(), local, None)?.ty;
|
||||
if Some(local) == body.spread_arg {
|
||||
|
@ -19,11 +19,11 @@ where
|
||||
}
|
||||
|
||||
struct FoundParam;
|
||||
struct UsedParamsNeedSubstVisitor<'tcx> {
|
||||
struct UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedSubstVisitor<'tcx> {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
type BreakTy = FoundParam;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
@ -34,21 +34,22 @@ where
|
||||
match *ty.kind() {
|
||||
ty::Param(_) => ControlFlow::Break(FoundParam),
|
||||
ty::Closure(def_id, args)
|
||||
| ty::CoroutineClosure(def_id, args, ..)
|
||||
| ty::Coroutine(def_id, args, ..)
|
||||
| ty::FnDef(def_id, args) => {
|
||||
let instance = ty::InstanceDef::Item(def_id);
|
||||
let unused_params = self.tcx.unused_generic_params(instance);
|
||||
for (index, subst) in args.into_iter().enumerate() {
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
let index = index
|
||||
.try_into()
|
||||
.expect("more generic parameters than can fit into a `u32`");
|
||||
// Only recurse when generic parameters in fns, closures and coroutines
|
||||
// are used and have to be instantiated.
|
||||
//
|
||||
// Just in case there are closures or coroutines within this subst,
|
||||
// Just in case there are closures or coroutines within this arg,
|
||||
// recurse.
|
||||
if unused_params.is_used(index) && subst.has_param() {
|
||||
return subst.visit_with(self);
|
||||
if unused_params.is_used(index) && arg.has_param() {
|
||||
return arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
@ -65,7 +66,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
let mut vis = UsedParamsNeedSubstVisitor { tcx };
|
||||
let mut vis = UsedParamsNeedInstantiationVisitor { tcx };
|
||||
if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
|
||||
throw_inval!(TooGeneric);
|
||||
} else {
|
||||
|
@ -240,8 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
|
||||
// Now we know we are projecting to a field, so figure out which one.
|
||||
match layout.ty.kind() {
|
||||
// coroutines and closures.
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
|
||||
// coroutines, closures, and coroutine-closures all have upvars that may be named.
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineClosure(def_id, _) => {
|
||||
let mut name = None;
|
||||
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
|
||||
// https://github.com/rust-lang/project-rfc-2229/issues/46
|
||||
|
@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
|
||||
|
||||
pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
|
||||
let did = self.def_id().to_def_id();
|
||||
if self.tcx.is_closure_or_coroutine(did) {
|
||||
if self.tcx.is_closure_like(did) {
|
||||
let ty = self.tcx.type_of(did).instantiate_identity();
|
||||
let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") };
|
||||
args.as_closure().sig()
|
||||
|
@ -22,9 +22,9 @@ fn foo<T>(x: Vec<T>) {
|
||||
In this specific case there's a good chance that the transmute is harmless (but
|
||||
this is not guaranteed by Rust). However, when alignment and enum optimizations
|
||||
come into the picture, it's quite likely that the sizes may or may not match
|
||||
with different type parameter substitutions. It's not possible to check this for
|
||||
_all_ possible types, so `transmute()` simply only accepts types without any
|
||||
unsubstituted type parameters.
|
||||
with different type parameter instantiations. It's not possible to check this
|
||||
for _all_ possible types, so `transmute()` simply only accepts types without any
|
||||
uninstantiated type parameters.
|
||||
|
||||
If you need this, there's a good chance you're doing something wrong. Keep in
|
||||
mind that Rust doesn't guarantee much about the layout of different structs
|
||||
@ -32,7 +32,7 @@ mind that Rust doesn't guarantee much about the layout of different structs
|
||||
there is a solution that avoids the transmute entirely, try it instead.
|
||||
|
||||
If it's possible, hand-monomorphize the code by writing the function for each
|
||||
possible type substitution. It's possible to use traits to do this cleanly,
|
||||
possible type instantiation. It's possible to use traits to do this cleanly,
|
||||
for example:
|
||||
|
||||
```
|
||||
|
@ -15,9 +15,9 @@ There will be an error about `bool` not implementing `Index<u8>`, followed by a
|
||||
note saying "the type `bool` cannot be indexed by `u8`".
|
||||
|
||||
As you can see, you can specify type parameters in curly braces for
|
||||
substitution with the actual types (using the regular format string syntax) in
|
||||
a given situation. Furthermore, `{Self}` will substitute to the type (in this
|
||||
case, `bool`) that we tried to use.
|
||||
instantiation with the actual types (using the regular format string syntax) in
|
||||
a given situation. Furthermore, `{Self}` will be instantiated to the type (in
|
||||
this case, `bool`) that we tried to use.
|
||||
|
||||
This error appears when the curly braces contain an identifier which doesn't
|
||||
match with any of the type parameters or the string `Self`. This might happen
|
||||
|
@ -15,9 +15,9 @@ there will be an error about `bool` not implementing `Index<u8>`, followed by a
|
||||
note saying "the type `bool` cannot be indexed by `u8`".
|
||||
|
||||
As you can see, you can specify type parameters in curly braces for
|
||||
substitution with the actual types (using the regular format string syntax) in
|
||||
a given situation. Furthermore, `{Self}` will substitute to the type (in this
|
||||
case, `bool`) that we tried to use.
|
||||
instantiation with the actual types (using the regular format string syntax) in
|
||||
a given situation. Furthermore, `{Self}` will be instantiated to the type (in
|
||||
this case, `bool`) that we tried to use.
|
||||
|
||||
This error appears when the curly braces do not contain an identifier. Please
|
||||
add one of the same name as a type parameter. If you intended to use literal
|
||||
|
@ -12,12 +12,12 @@ fn together_we_will_rule_the_galaxy(son: &A) {}
|
||||
```
|
||||
|
||||
A trait object is defined over a single, fully-defined trait. With a regular
|
||||
default parameter, this parameter can just be substituted in. However, if the
|
||||
default parameter, this parameter can just be instantiated in. However, if the
|
||||
default parameter is `Self`, the trait changes for each concrete type; i.e.
|
||||
`i32` will be expected to implement `A<i32>`, `bool` will be expected to
|
||||
implement `A<bool>`, etc... These types will not share an implementation of a
|
||||
fully-defined trait; instead they share implementations of a trait with
|
||||
different parameters substituted in for each implementation. This is
|
||||
different parameters instantiated in for each implementation. This is
|
||||
irreconcilable with what we need to make a trait object work, and is thus
|
||||
disallowed. Making the trait concrete by explicitly specifying the value of the
|
||||
defaulted parameter will fix this issue. Fixed example:
|
||||
|
@ -14,7 +14,7 @@ let _ = foo::<'static>;
|
||||
|
||||
The type of a concrete instance of a generic function is universally quantified
|
||||
over late-bound lifetime parameters. This is because we want the function to
|
||||
work for any lifetime substituted for the late-bound lifetime parameter, no
|
||||
work for any lifetime instantiated for the late-bound lifetime parameter, no
|
||||
matter where the function is called. Consequently, it doesn't make sense to
|
||||
specify arguments for late-bound lifetime parameters, since they are not
|
||||
resolved until the function's call site(s).
|
||||
@ -56,7 +56,7 @@ let bar_fn3 = bar::<Bar>; // OK
|
||||
|
||||
In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
|
||||
`'b` is early-bound. This is reflected in the type annotation for `bar_fn`,
|
||||
where `'a` is universally quantified and `'b` is substituted by a specific
|
||||
where `'a` is universally quantified and `'b` is instantiated with a specific
|
||||
lifetime. It is not allowed to explicitly specify early-bound lifetime
|
||||
arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
|
||||
see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although
|
||||
|
@ -301,9 +301,11 @@ declare_features! (
|
||||
(unstable, csky_target_feature, "1.73.0", Some(44839)),
|
||||
(unstable, ermsb_target_feature, "1.49.0", Some(44839)),
|
||||
(unstable, hexagon_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, lahfsahf_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
(unstable, loongarch_target_feature, "1.73.0", Some(44839)),
|
||||
(unstable, mips_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, powerpc_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, prfchw_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
|
||||
(unstable, rtm_target_feature, "1.35.0", Some(44839)),
|
||||
(unstable, sse4a_target_feature, "1.27.0", Some(44839)),
|
||||
|
@ -116,6 +116,12 @@ pub enum DefKind {
|
||||
Impl {
|
||||
of_trait: bool,
|
||||
},
|
||||
/// A closure, coroutine, or coroutine-closure.
|
||||
///
|
||||
/// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
|
||||
/// which makes it difficult to distinguish these during def collection. Therefore,
|
||||
/// we treat them all the same, and code which needs to distinguish them can match
|
||||
/// or `hir::ClosureKind` or `type_of`.
|
||||
Closure,
|
||||
}
|
||||
|
||||
|
@ -2536,7 +2536,7 @@ pub struct OpaqueTy<'hir> {
|
||||
/// lifetimes that are captured from the function signature they originate from.
|
||||
///
|
||||
/// This is done by generating a new early-bound lifetime parameter local to the
|
||||
/// opaque which is substituted in the function signature with the late-bound
|
||||
/// opaque which is instantiated in the function signature with the late-bound
|
||||
/// lifetime.
|
||||
///
|
||||
/// This mapping associated a captured lifetime (first parameter) with the new
|
||||
|
@ -153,6 +153,8 @@ hir_analysis_function_not_have_default_implementation = function doesn't have a
|
||||
hir_analysis_functions_names_duplicated = functions names are duplicated
|
||||
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
|
||||
|
||||
hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl
|
||||
|
||||
hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
.label = cannot specialize default item `{$ident}`
|
||||
.ok_label = parent `impl` is here
|
||||
@ -387,8 +389,6 @@ hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is disco
|
||||
|
||||
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
|
||||
|
||||
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
|
||||
|
||||
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
|
||||
.note = this item must mention the opaque type in its signature in order to be able to register hidden types
|
||||
|
||||
|
@ -336,12 +336,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
|
||||
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
|
||||
let mut emitted_bad_param_err = None;
|
||||
// If we have an method return type bound, then we need to substitute
|
||||
// If we have an method return type bound, then we need to instantiate
|
||||
// the method's early bound params with suitable late-bound params.
|
||||
let mut num_bound_vars = candidate.bound_vars().len();
|
||||
let args =
|
||||
candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| {
|
||||
let subst = match param.kind {
|
||||
let arg = match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
@ -379,7 +379,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
}
|
||||
};
|
||||
num_bound_vars += 1;
|
||||
subst
|
||||
arg
|
||||
});
|
||||
|
||||
// Next, we need to check that the return-type notation is being used on
|
||||
@ -402,12 +402,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
|
||||
// Finally, move the fn return type's bound vars over to account for the early bound
|
||||
// params (and trait ref's late bound params). This logic is very similar to
|
||||
// `Predicate::subst_supertrait`, and it's no coincidence why.
|
||||
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
|
||||
// and it's no coincidence why.
|
||||
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
|
||||
let subst_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
|
||||
let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
|
||||
|
||||
let bound_vars = tcx.late_bound_vars(binding.hir_id);
|
||||
ty::Binder::bind_with_vars(subst_output, bound_vars)
|
||||
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
|
||||
} else {
|
||||
// Append the generic arguments of the associated type to the `trait_ref`.
|
||||
candidate.map_bound(|trait_ref| {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::IsMethodCall;
|
||||
use crate::astconv::{
|
||||
errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound,
|
||||
errors::prohibit_assoc_ty_binding, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound,
|
||||
GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
|
||||
};
|
||||
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
|
||||
@ -177,9 +177,9 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
|
||||
has_self: bool,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
arg_count: &GenericArgCountResult,
|
||||
ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
|
||||
ctx: &mut impl CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
// Collect the segments of the path; we need to substitute arguments
|
||||
// Collect the segments of the path; we need to instantiate arguments
|
||||
// for parameters throughout the entire path (wherever there are
|
||||
// generic parameters).
|
||||
let mut parent_defs = tcx.generics_of(def_id);
|
||||
@ -191,7 +191,7 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
|
||||
}
|
||||
|
||||
// We manually build up the generic arguments, rather than using convenience
|
||||
// methods in `subst.rs`, so that we can iterate over the arguments and
|
||||
// methods in `rustc_middle/src/ty/generic_args.rs`, so that we can iterate over the arguments and
|
||||
// parameters in lock-step linearly, instead of trying to match each pair.
|
||||
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
|
||||
// Iterate over each segment of the path.
|
||||
|
@ -214,7 +214,7 @@ pub struct GenericArgCountResult {
|
||||
pub correct: Result<(), GenericArgCountMismatch>,
|
||||
}
|
||||
|
||||
pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
|
||||
pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
|
||||
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool);
|
||||
|
||||
fn provided_kind(
|
||||
@ -366,8 +366,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
|
||||
if generics.has_self {
|
||||
if generics.parent.is_some() {
|
||||
// The parent is a trait so it should have at least one subst
|
||||
// for the `Self` type.
|
||||
// The parent is a trait so it should have at least one
|
||||
// generic parameter for the `Self` type.
|
||||
assert!(!parent_args.is_empty())
|
||||
} else {
|
||||
// This item (presumably a trait) needs a self-type.
|
||||
@ -402,7 +402,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
return (tcx.mk_args(parent_args), arg_count);
|
||||
}
|
||||
|
||||
struct SubstsForAstPathCtxt<'a, 'tcx> {
|
||||
struct InstantiationsForAstPathCtxt<'a, 'tcx> {
|
||||
astconv: &'a (dyn AstConv<'tcx> + 'a),
|
||||
def_id: DefId,
|
||||
generic_args: &'a GenericArgs<'tcx>,
|
||||
@ -411,7 +411,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
infer_args: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
|
||||
impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
|
||||
for InstantiationsForAstPathCtxt<'a, 'tcx>
|
||||
{
|
||||
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) {
|
||||
if did == self.def_id {
|
||||
(Some(self.generic_args), self.infer_args)
|
||||
@ -556,7 +558,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
}
|
||||
|
||||
let mut args_ctx = SubstsForAstPathCtxt {
|
||||
let mut args_ctx = InstantiationsForAstPathCtxt {
|
||||
astconv: self,
|
||||
def_id,
|
||||
span,
|
||||
@ -2412,8 +2414,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
|
||||
let self_ty = self.tcx().type_of(parent).instantiate_identity();
|
||||
let generic_self_ty = ty::GenericArg::from(self_ty);
|
||||
let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
|
||||
sig.instantiate(self.tcx(), substs)
|
||||
let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
|
||||
sig.instantiate(self.tcx(), args)
|
||||
} else {
|
||||
sig.instantiate_identity()
|
||||
};
|
||||
|
@ -175,7 +175,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be substituted with a
|
||||
// A `Self` within the original bound will be instantiated with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self = match pred.skip_binder().term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
|
@ -1083,7 +1083,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
||||
match t.kind() {
|
||||
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
|
||||
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
|
||||
ty::Adt(def, subst) => {
|
||||
ty::Adt(def, args) => {
|
||||
if !def.did().is_local() {
|
||||
let non_exhaustive = def.is_variant_list_non_exhaustive()
|
||||
|| def
|
||||
@ -1095,13 +1095,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
||||
return ControlFlow::Break((
|
||||
def.descr(),
|
||||
def.did(),
|
||||
subst,
|
||||
args,
|
||||
non_exhaustive,
|
||||
));
|
||||
}
|
||||
}
|
||||
def.all_fields()
|
||||
.map(|field| field.ty(tcx, subst))
|
||||
.map(|field| field.ty(tcx, args))
|
||||
.try_for_each(|t| check_non_exhaustive(tcx, t))
|
||||
}
|
||||
_ => ControlFlow::Continue(()),
|
||||
|
@ -125,9 +125,9 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
|
||||
/// ```
|
||||
///
|
||||
/// We now want to extract and substitute the type of the *trait*
|
||||
/// We now want to extract and instantiate the type of the *trait*
|
||||
/// method and compare it. To do so, we must create a compound
|
||||
/// substitution by combining `trait_to_impl_args` and
|
||||
/// instantiation by combining `trait_to_impl_args` and
|
||||
/// `impl_to_placeholder_args`, and also adding a mapping for the method
|
||||
/// type parameters. We extend the mapping to also include
|
||||
/// the method parameters.
|
||||
@ -146,11 +146,11 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||
/// vs `'b`). However, the normal subtyping rules on fn types handle
|
||||
/// this kind of equivalency just fine.
|
||||
///
|
||||
/// We now use these substitutions to ensure that all declared bounds are
|
||||
/// satisfied by the implementation's method.
|
||||
/// We now use these generic parameters to ensure that all declared bounds
|
||||
/// are satisfied by the implementation's method.
|
||||
///
|
||||
/// We do this by creating a parameter environment which contains a
|
||||
/// substitution corresponding to `impl_to_placeholder_args`. We then build
|
||||
/// generic parameter corresponding to `impl_to_placeholder_args`. We then build
|
||||
/// `trait_to_placeholder_args` and use it to convert the predicates contained
|
||||
/// in the `trait_m` generics to the placeholder form.
|
||||
///
|
||||
@ -454,7 +454,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
|
||||
// First, check a few of the same things as `compare_impl_method`,
|
||||
// just so we don't ICE during substitution later.
|
||||
// just so we don't ICE during instantiation later.
|
||||
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
|
||||
|
||||
let trait_to_impl_args = impl_trait_ref.args;
|
||||
@ -543,7 +543,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
// }
|
||||
// ```
|
||||
// .. to compile. However, since we use both the normalized and unnormalized
|
||||
// inputs and outputs from the substituted trait signature, we will end up
|
||||
// inputs and outputs from the instantiated trait signature, we will end up
|
||||
// seeing the hidden type of an RPIT in the signature itself. Naively, this
|
||||
// means that we will use the hidden type to imply the hidden type's own
|
||||
// well-formedness.
|
||||
@ -699,7 +699,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
|
||||
// region args that are synthesized during AST lowering. These are args
|
||||
// that are appended to the parent args (trait and trait method). However,
|
||||
// we're trying to infer the unsubstituted type value of the RPITIT inside
|
||||
// we're trying to infer the uninstantiated type value of the RPITIT inside
|
||||
// the *impl*, so we can later use the impl's method args to normalize
|
||||
// an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
|
||||
//
|
||||
@ -711,7 +711,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
// guarantee that the indices from the trait args and impl args line up.
|
||||
// So to fix this, we subtract the number of trait args and add the number of
|
||||
// impl args to *renumber* these early-bound regions to their corresponding
|
||||
// indices in the impl's substitutions list.
|
||||
// indices in the impl's generic parameters list.
|
||||
//
|
||||
// Also, we only need to account for a difference in trait and impl args,
|
||||
// since we previously enforce that the trait method and impl method have the
|
||||
|
@ -124,14 +124,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
// Take the param-env of the adt and substitute the args that show up in
|
||||
// Take the param-env of the adt and instantiate the args that show up in
|
||||
// the implementation's self type. This gives us the assumptions that the
|
||||
// self ty of the implementation is allowed to know just from it being a
|
||||
// well-formed adt, since that's all we're allowed to assume while proving
|
||||
// the Drop implementation is not specialized.
|
||||
//
|
||||
// We don't need to normalize this param-env or anything, since we're only
|
||||
// substituting it with free params, so no additional param-env normalization
|
||||
// instantiating it with free params, so no additional param-env normalization
|
||||
// can occur on top of what has been done in the param_env query itself.
|
||||
let param_env =
|
||||
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
|
||||
|
@ -56,7 +56,7 @@ type variable is an instance of a type parameter. That is,
|
||||
given a generic function `fn foo<T>(t: T)`, while checking the
|
||||
function `foo`, the type `ty_param(0)` refers to the type `T`, which
|
||||
is treated in abstract. However, when `foo()` is called, `T` will be
|
||||
substituted for a fresh type variable `N`. This variable will
|
||||
instantiated with a fresh type variable `N`. This variable will
|
||||
eventually be resolved to some concrete type (which might itself be
|
||||
a type parameter).
|
||||
|
||||
|
@ -618,7 +618,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
// The bounds we that we would require from `to_check`
|
||||
let mut bounds = FxHashSet::default();
|
||||
|
||||
let (regions, types) = GATSubstCollector::visit(gat_def_id.to_def_id(), to_check);
|
||||
let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check);
|
||||
|
||||
// If both regions and types are empty, then this GAT isn't in the
|
||||
// set of types we are checking, and we shouldn't try to do clause analysis
|
||||
@ -787,34 +787,34 @@ fn test_region_obligations<'tcx>(
|
||||
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
|
||||
/// the two vectors, `regions` and `types` (depending on their kind). For each
|
||||
/// parameter `Pi` also track the index `i`.
|
||||
struct GATSubstCollector<'tcx> {
|
||||
struct GATArgsCollector<'tcx> {
|
||||
gat: DefId,
|
||||
// Which region appears and which parameter index its substituted for
|
||||
// Which region appears and which parameter index its instantiated with
|
||||
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
|
||||
// Which params appears and which parameter index its substituted for
|
||||
// Which params appears and which parameter index its instantiated with
|
||||
types: FxHashSet<(Ty<'tcx>, usize)>,
|
||||
}
|
||||
|
||||
impl<'tcx> GATSubstCollector<'tcx> {
|
||||
impl<'tcx> GATArgsCollector<'tcx> {
|
||||
fn visit<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
gat: DefId,
|
||||
t: T,
|
||||
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
|
||||
let mut visitor =
|
||||
GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
|
||||
GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
|
||||
t.visit_with(&mut visitor);
|
||||
(visitor.regions, visitor.types)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATSubstCollector<'tcx> {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
|
||||
type BreakTy = !;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match t.kind() {
|
||||
ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
|
||||
for (idx, subst) in p.args.iter().enumerate() {
|
||||
match subst.unpack() {
|
||||
for (idx, arg) in p.args.iter().enumerate() {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(lt) if !lt.is_bound() => {
|
||||
self.regions.insert((lt, idx));
|
||||
}
|
||||
@ -1407,14 +1407,14 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
}
|
||||
}
|
||||
|
||||
// Check that trait predicates are WF when params are substituted by their defaults.
|
||||
// Check that trait predicates are WF when params are instantiated with their defaults.
|
||||
// We don't want to overly constrain the predicates that may be written but we want to
|
||||
// catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
|
||||
// Therefore we check if a predicate which contains a single type param
|
||||
// with a concrete default is WF with that default substituted.
|
||||
// with a concrete default is WF with that default instantiated.
|
||||
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
|
||||
//
|
||||
// First we build the defaulted substitution.
|
||||
// First we build the defaulted generic parameters.
|
||||
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
let default_ty = tcx.type_of(param.def_id).instantiate_identity();
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ty.has_param() {
|
||||
// ... then substitute it with the default.
|
||||
// ... then instantiate it with the default.
|
||||
return default_ty.into();
|
||||
}
|
||||
}
|
||||
@ -1441,7 +1441,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ct.has_param() {
|
||||
// ... then substitute it with the default.
|
||||
// ... then instantiate it with the default.
|
||||
return default_ct.into();
|
||||
}
|
||||
}
|
||||
@ -1451,7 +1451,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
}
|
||||
});
|
||||
|
||||
// Now we build the substituted predicates.
|
||||
// Now we build the instantiated predicates.
|
||||
let default_obligations = predicates
|
||||
.predicates
|
||||
.iter()
|
||||
@ -1483,23 +1483,25 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
}
|
||||
let mut param_count = CountParams::default();
|
||||
let has_region = pred.visit_with(&mut param_count).is_break();
|
||||
let substituted_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
|
||||
let instantiated_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
|
||||
// Don't check non-defaulted params, dependent defaults (including lifetimes)
|
||||
// or preds with multiple params.
|
||||
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
|
||||
if instantiated_pred.has_non_region_param()
|
||||
|| param_count.params.len() > 1
|
||||
|| has_region
|
||||
{
|
||||
None
|
||||
} else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
|
||||
} else if predicates.predicates.iter().any(|&(p, _)| p == instantiated_pred) {
|
||||
// Avoid duplication of predicates that contain no parameters, for example.
|
||||
None
|
||||
} else {
|
||||
Some((substituted_pred, sp))
|
||||
Some((instantiated_pred, sp))
|
||||
}
|
||||
})
|
||||
.map(|(pred, sp)| {
|
||||
// Convert each of those into an obligation. So if you have
|
||||
// something like `struct Foo<T: Copy = String>`, we would
|
||||
// take that predicate `T: Copy`, substitute to `String: Copy`
|
||||
// take that predicate `T: Copy`, instantiated with `String: Copy`
|
||||
// (actually that happens in the previous `flat_map` call),
|
||||
// and then try to prove it (in this case, we'll fail).
|
||||
//
|
||||
|
@ -396,7 +396,7 @@ pub fn coerce_unsized_info<'tcx>(
|
||||
//
|
||||
// To check if this impl is legal, we would walk down
|
||||
// the fields of `Foo` and consider their types with
|
||||
// both substitutes. We are looking to find that
|
||||
// both generic parameters. We are looking to find that
|
||||
// exactly one (non-phantom) field has changed its
|
||||
// type, which we will expect to be the pointer that
|
||||
// is becoming fat (we could probably generalize this
|
||||
|
@ -71,7 +71,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
// end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`.
|
||||
//
|
||||
// This causes ICEs (#86580) when building the args for Foo in `fn foo() -> Foo { .. }` as
|
||||
// we substitute the defaults with the partially built args when we build the args. Subst'ing
|
||||
// we instantiate the defaults with the partially built args when we build the args. Instantiating
|
||||
// the `N#0` on the unevaluated const indexes into the empty args we're in the process of building.
|
||||
//
|
||||
// We fix this by having this function return the parent's generics ourselves and truncating the
|
||||
|
@ -1786,7 +1786,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::ClauseKind::Trait(data) => {
|
||||
// The order here needs to match what we would get from `subst_supertrait`
|
||||
// The order here needs to match what we would get from
|
||||
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
|
||||
let pred_bound_vars = bound_predicate.bound_vars();
|
||||
let mut all_bound_vars = bound_vars.clone();
|
||||
all_bound_vars.extend(pred_bound_vars.iter());
|
||||
|
@ -119,7 +119,7 @@ pub fn identify_constrained_generic_params<'tcx>(
|
||||
/// * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
|
||||
///
|
||||
/// When we, for example, try to go over the trait-reference
|
||||
/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
|
||||
/// `IntoIter<u32> as Trait`, we instantiate the impl parameters with fresh
|
||||
/// variables and match them with the impl trait-ref, so we know that
|
||||
/// `$U = IntoIter<u32>`.
|
||||
///
|
||||
|
@ -424,8 +424,8 @@ pub struct ManualImplementation {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_substs_on_overridden_impl)]
|
||||
pub struct SubstsOnOverriddenImpl {
|
||||
#[diag(hir_analysis_generic_args_on_overridden_impl)]
|
||||
pub struct GenericArgsOnOverriddenImpl {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -34,8 +34,8 @@
|
||||
//! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
|
||||
//! ```
|
||||
//!
|
||||
//! We get that the subst for `impl2` are `[T, std::vec::IntoIter<T>]`. `T` is
|
||||
//! constrained to be `<I as Iterator>::Item`, so we check only
|
||||
//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
|
||||
//! `T` is constrained to be `<I as Iterator>::Item`, so we check only
|
||||
//! `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The
|
||||
//! predicates of `impl1` are only `T: Sized`, which is also a predicate of
|
||||
//! `impl2`. So this specialization is sound.
|
||||
@ -65,7 +65,7 @@
|
||||
//! cause use after frees with purely safe code in the same way as specializing
|
||||
//! on traits with methods can.
|
||||
|
||||
use crate::errors::SubstsOnOverriddenImpl;
|
||||
use crate::errors::GenericArgsOnOverriddenImpl;
|
||||
use crate::{constrained_generic_params as cgp, errors};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -179,8 +179,8 @@ fn check_constness(
|
||||
}
|
||||
|
||||
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
|
||||
/// substitutions `(S1, S2)` that equate their trait references. The returned
|
||||
/// types are expressed in terms of the generics of `impl1`.
|
||||
/// generic parameters `(S1, S2)` that equate their trait references.
|
||||
/// The returned types are expressed in terms of the generics of `impl1`.
|
||||
///
|
||||
/// Example
|
||||
///
|
||||
@ -228,13 +228,13 @@ fn get_impl_args(
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
|
||||
let span = tcx.def_span(impl1_def_id);
|
||||
let guar = tcx.dcx().emit_err(SubstsOnOverriddenImpl { span });
|
||||
let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
|
||||
return Err(guar);
|
||||
};
|
||||
Ok((impl1_args, impl2_args))
|
||||
}
|
||||
|
||||
/// Returns a list of all of the unconstrained subst of the given impl.
|
||||
/// Returns a list of all of the unconstrained generic parameters of the given impl.
|
||||
///
|
||||
/// For example given the impl:
|
||||
///
|
||||
|
@ -229,7 +229,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
||||
/// Here, we should fetch the explicit predicates, which
|
||||
/// will give us `U: 'static` and `U: Outer`. The latter we
|
||||
/// can ignore, but we will want to process `U: 'static`,
|
||||
/// applying the substitution as above.
|
||||
/// applying the instantiation as above.
|
||||
fn check_explicit_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
@ -316,7 +316,7 @@ fn check_explicit_predicates<'tcx>(
|
||||
/// Here, when processing the type of field `outer`, we would request the
|
||||
/// set of implicit predicates computed for `Inner` thus far. This will
|
||||
/// initially come back empty, but in next round we will get `U: 'b`.
|
||||
/// We then apply the substitution `['b => 'a, U => T]` and thus get the
|
||||
/// We then apply the instantiation `['b => 'a, U => T]` and thus get the
|
||||
/// requirement that `T: 'a` holds for `Outer`.
|
||||
fn check_inferred_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -334,7 +334,7 @@ fn check_inferred_predicates<'tcx>(
|
||||
|
||||
for (&predicate, &span) in predicates.as_ref().skip_binder() {
|
||||
// `predicate` is `U: 'b` in the example above.
|
||||
// So apply the substitution to get `T: 'a`.
|
||||
// So apply the instantiation to get `T: 'a`.
|
||||
let ty::OutlivesPredicate(arg, region) =
|
||||
predicates.rebind(predicate).instantiate(tcx, args);
|
||||
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
|
||||
|
@ -172,16 +172,16 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||
trait_ref: ty::TraitRef { def_id: _, args, .. },
|
||||
polarity: _,
|
||||
}) => {
|
||||
for subst in &args[1..] {
|
||||
subst.visit_with(&mut collector);
|
||||
for arg in &args[1..] {
|
||||
arg.visit_with(&mut collector);
|
||||
}
|
||||
}
|
||||
ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy { args, .. },
|
||||
term,
|
||||
}) => {
|
||||
for subst in &args[1..] {
|
||||
subst.visit_with(&mut collector);
|
||||
for arg in &args[1..] {
|
||||
arg.visit_with(&mut collector);
|
||||
}
|
||||
term.visit_with(&mut collector);
|
||||
}
|
||||
|
@ -90,8 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
// ty.span == binding_span iff this is a closure parameter with no type ascription,
|
||||
// or if it's an implicit `self` parameter
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
|
||||
{
|
||||
if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
|
||||
None
|
||||
} else {
|
||||
ty.map(|ty| ty.hir_id)
|
||||
@ -123,7 +122,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
||||
// We have special-cased the case where the function is declared
|
||||
// `-> dyn Foo` and we don't actually relate it to the
|
||||
// `fcx.ret_coercion`, so just substitute a type variable.
|
||||
// `fcx.ret_coercion`, so just instantiate a type variable.
|
||||
actual_return_ty =
|
||||
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
|
||||
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
|
||||
|
@ -752,7 +752,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
let mut obligations: Vec<_> = predicates
|
||||
.iter()
|
||||
.map(|predicate| {
|
||||
// For each existential predicate (e.g., `?Self: Clone`) substitute
|
||||
// For each existential predicate (e.g., `?Self: Clone`) instantiate
|
||||
// the type of the expression (e.g., `usize` in our example above)
|
||||
// and then require that the resulting predicate (e.g., `usize: Clone`)
|
||||
// holds (it does).
|
||||
|
@ -1801,7 +1801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// consistency. But they should be merged as much as possible.
|
||||
let fru_tys = if self.tcx.features().type_changing_struct_update {
|
||||
if adt.is_struct() {
|
||||
// Make some fresh substitutions for our ADT type.
|
||||
// Make some fresh generic parameters for our ADT type.
|
||||
let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did());
|
||||
// We do subtyping on the FRU fields first, so we can
|
||||
// learn exactly what types we expect the base expr
|
||||
|
@ -15,7 +15,7 @@ use rustc_hir_analysis::astconv::generics::{
|
||||
check_generic_arg_count_for_call, create_args_for_parent_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::{
|
||||
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||
AstConv, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||
GenericArgCountResult, IsMethodCall, PathSeg,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
@ -187,8 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Given the args that we just converted from the HIR, try to
|
||||
/// canonicalize them and store them as user-given substitutions
|
||||
/// (i.e., substitutions that must be respected by the NLL check).
|
||||
/// canonicalize them and store them as user-given parameters
|
||||
/// (i.e., parameters that must be respected by the NLL check).
|
||||
///
|
||||
/// This should be invoked **before any unifications have
|
||||
/// occurred**, so that annotations like `Vec<_>` are preserved
|
||||
@ -741,7 +741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
|
||||
// Record all the argument types, with the substitutions
|
||||
// Record all the argument types, with the args
|
||||
// produced from the above subtyping unification.
|
||||
Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()))
|
||||
})
|
||||
@ -1171,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Now we have to compare the types that the user *actually*
|
||||
// provided against the types that were *expected*. If the user
|
||||
// did not provide any types, then we want to substitute inference
|
||||
// did not provide any types, then we want to instantiate inference
|
||||
// variables. If the user provided some types, we may still need
|
||||
// to add defaults. If the user provided *too many* types, that's
|
||||
// a problem.
|
||||
@ -1261,14 +1261,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
},
|
||||
};
|
||||
|
||||
struct CreateCtorSubstsContext<'a, 'tcx> {
|
||||
struct CreateCtorInstantiationsContext<'a, 'tcx> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
path_segs: &'a [PathSeg],
|
||||
infer_args_for_err: &'a FxHashSet<usize>,
|
||||
segments: &'tcx [hir::PathSegment<'tcx>],
|
||||
}
|
||||
impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> {
|
||||
impl<'tcx, 'a> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
|
||||
for CreateCtorInstantiationsContext<'a, 'tcx>
|
||||
{
|
||||
fn args_for_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
@ -1392,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
has_self,
|
||||
self_ty.map(|s| s.raw),
|
||||
&arg_count,
|
||||
&mut CreateCtorSubstsContext {
|
||||
&mut CreateCtorInstantiationsContext {
|
||||
fcx: self,
|
||||
span,
|
||||
path_segs: &path_segs,
|
||||
@ -1410,18 +1412,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
self.add_required_obligations_for_hir(span, def_id, args, hir_id);
|
||||
|
||||
// Substitute the values for the type parameters into the type of
|
||||
// Instantiate the values for the type parameters into the type of
|
||||
// the referenced item.
|
||||
let ty = tcx.type_of(def_id);
|
||||
assert!(!args.has_escaping_bound_vars());
|
||||
assert!(!ty.skip_binder().has_escaping_bound_vars());
|
||||
let ty_substituted = self.normalize(span, ty.instantiate(tcx, args));
|
||||
let ty_instantiated = self.normalize(span, ty.instantiate(tcx, args));
|
||||
|
||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||
// In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
|
||||
// is inherent, there is no `Self` parameter; instead, the impl needs
|
||||
// type parameters, which we can infer by unifying the provided `Self`
|
||||
// with the substituted impl type.
|
||||
// with the instantiated impl type.
|
||||
// This also occurs for an enum variant on a type alias.
|
||||
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
|
||||
let self_ty = self.normalize(span, self_ty);
|
||||
@ -1442,13 +1444,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
|
||||
debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_instantiated);
|
||||
self.write_args(hir_id, args);
|
||||
|
||||
(ty_substituted, res)
|
||||
(ty_instantiated, res)
|
||||
}
|
||||
|
||||
/// Add all the obligations that are required, substituting and normalized appropriately.
|
||||
/// Add all the obligations that are required, instantiated and normalized appropriately.
|
||||
pub(crate) fn add_required_obligations_for_hir(
|
||||
&self,
|
||||
span: Span,
|
||||
|
@ -21,7 +21,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(unsubstituted_pred) = self
|
||||
let Some(uninstantiated_pred) = self
|
||||
.tcx
|
||||
.predicates_of(def_id)
|
||||
.instantiate_identity(self.tcx)
|
||||
@ -34,7 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let (predicate_args, predicate_self_type_to_point_at) =
|
||||
match unsubstituted_pred.kind().skip_binder() {
|
||||
match uninstantiated_pred.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(pred) => {
|
||||
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
|
||||
}
|
||||
@ -343,10 +343,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
|
||||
&& let generics = self.0.tcx.generics_of(self.1)
|
||||
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
|
||||
&& let Some(subst) =
|
||||
&& let Some(arg) =
|
||||
ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
|
||||
{
|
||||
ControlFlow::Break(*subst)
|
||||
ControlFlow::Break(*arg)
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
|
@ -2133,17 +2133,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expr_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let (adt, substs, unwrap) = match expected.kind() {
|
||||
let (adt, args, unwrap) = match expected.kind() {
|
||||
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
|
||||
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
|
||||
let nonzero_type = substs.type_at(0); // Unwrap option type.
|
||||
let ty::Adt(adt, substs) = nonzero_type.kind() else {
|
||||
ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
|
||||
let nonzero_type = args.type_at(0); // Unwrap option type.
|
||||
let ty::Adt(adt, args) = nonzero_type.kind() else {
|
||||
return false;
|
||||
};
|
||||
(adt, substs, "")
|
||||
(adt, args, "")
|
||||
}
|
||||
// In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types.
|
||||
ty::Adt(adt, substs) => (adt, substs, ".unwrap()"),
|
||||
ty::Adt(adt, args) => (adt, args, ".unwrap()"),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
@ -2165,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
("NonZeroI128", tcx.types.i128),
|
||||
];
|
||||
|
||||
let int_type = substs.type_at(0);
|
||||
let int_type = args.type_at(0);
|
||||
|
||||
let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| {
|
||||
if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None }
|
||||
|
@ -153,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||
// ascription, or if it's an implicit `self` parameter
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == ident.span
|
||||
&& self.fcx.tcx.is_closure_or_coroutine(self.fcx.body_id.into())
|
||||
&& self.fcx.tcx.is_closure_like(self.fcx.body_id.into())
|
||||
{
|
||||
None
|
||||
} else {
|
||||
|
@ -7,7 +7,7 @@ use rustc_hir::GenericArg;
|
||||
use rustc_hir_analysis::astconv::generics::{
|
||||
check_generic_arg_count_for_call, create_args_for_parent_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
||||
use rustc_hir_analysis::astconv::{AstConv, CreateInstantiationsForGenericArgsCtxt, IsMethodCall};
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
@ -95,7 +95,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
// Adjust the self expression the user provided and obtain the adjusted type.
|
||||
let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick);
|
||||
|
||||
// Create substitutions for the method's type parameters.
|
||||
// Create generic args for the method's type parameters.
|
||||
let rcvr_args = self.fresh_receiver_args(self_ty, pick);
|
||||
let all_args = self.instantiate_method_args(pick, segment, rcvr_args);
|
||||
|
||||
@ -246,11 +246,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
target
|
||||
}
|
||||
|
||||
/// Returns a set of substitutions for the method *receiver* where all type and region
|
||||
/// parameters are instantiated with fresh variables. This substitution does not include any
|
||||
/// Returns a set of generic parameters for the method *receiver* where all type and region
|
||||
/// parameters are instantiated with fresh variables. This generic paramters does not include any
|
||||
/// parameters declared on the method itself.
|
||||
///
|
||||
/// Note that this substitution may include late-bound regions from the impl level. If so,
|
||||
/// Note that this generic parameters may include late-bound regions from the impl level. If so,
|
||||
/// these are instantiated later in the `instantiate_method_sig` routine.
|
||||
fn fresh_receiver_args(
|
||||
&mut self,
|
||||
@ -272,8 +272,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
|
||||
// The object data has no entry for the Self
|
||||
// Type. For the purposes of this method call, we
|
||||
// substitute the object type itself. This
|
||||
// wouldn't be a sound substitution in all cases,
|
||||
// instantiate the object type itself. This
|
||||
// wouldn't be a sound instantiation in all cases,
|
||||
// since each instance of the object type is a
|
||||
// different existential and hence could match
|
||||
// distinct types (e.g., if `Self` appeared as an
|
||||
@ -362,16 +362,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
IsMethodCall::Yes,
|
||||
);
|
||||
|
||||
// Create subst for early-bound lifetime parameters, combining
|
||||
// parameters from the type and those from the method.
|
||||
// Create generic paramters for early-bound lifetime parameters,
|
||||
// combining parameters from the type and those from the method.
|
||||
assert_eq!(generics.parent_count, parent_args.len());
|
||||
|
||||
struct MethodSubstsCtxt<'a, 'tcx> {
|
||||
struct MethodInstantiationsCtxt<'a, 'tcx> {
|
||||
cfcx: &'a ConfirmContext<'a, 'tcx>,
|
||||
pick: &'a probe::Pick<'tcx>,
|
||||
seg: &'a hir::PathSegment<'tcx>,
|
||||
}
|
||||
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> {
|
||||
impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
|
||||
for MethodInstantiationsCtxt<'a, 'tcx>
|
||||
{
|
||||
fn args_for_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
@ -437,7 +439,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
false,
|
||||
None,
|
||||
&arg_count_correct,
|
||||
&mut MethodSubstsCtxt { cfcx: self, pick, seg },
|
||||
&mut MethodInstantiationsCtxt { cfcx: self, pick, seg },
|
||||
);
|
||||
|
||||
// When the method is confirmed, the `args` includes
|
||||
@ -538,15 +540,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
|
||||
|
||||
// Instantiate the bounds on the method with the
|
||||
// type/early-bound-regions substitutions performed. There can
|
||||
// type/early-bound-regions instatiations performed. There can
|
||||
// be no late-bound regions appearing here.
|
||||
let def_id = pick.item.def_id;
|
||||
let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
|
||||
|
||||
debug!("method_predicates after subst = {:?}", method_predicates);
|
||||
debug!("method_predicates after instantitation = {:?}", method_predicates);
|
||||
|
||||
let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
|
||||
debug!("type scheme substituted, sig={:?}", sig);
|
||||
debug!("type scheme instantiated, sig={:?}", sig);
|
||||
|
||||
let sig = self.instantiate_binder_with_fresh_vars(sig);
|
||||
debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
|
||||
|
@ -38,7 +38,7 @@ pub struct MethodCallee<'tcx> {
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
|
||||
/// Instantiated method signature, i.e., it has been
|
||||
/// substituted, normalized, and has had late-bound
|
||||
/// instantiated, normalized, and has had late-bound
|
||||
/// lifetimes replaced with inference variables.
|
||||
pub sig: ty::FnSig<'tcx>,
|
||||
}
|
||||
@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
|
||||
let mut obligations = vec![];
|
||||
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// Instantiate late-bound regions and instantiate the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
//
|
||||
// N.B., instantiate late-bound regions before normalizing the
|
||||
|
@ -111,7 +111,7 @@ pub(crate) struct Candidate<'tcx> {
|
||||
// The way this is handled is through `xform_self_ty`. It contains
|
||||
// the receiver type of this candidate, but `xform_self_ty`,
|
||||
// `xform_ret_ty` and `kind` (which contains the predicates) have the
|
||||
// generic parameters of this candidate substituted with the *same set*
|
||||
// generic parameters of this candidate instantiated with the *same set*
|
||||
// of inference variables, which acts as some weird sort of "query".
|
||||
//
|
||||
// When we check out a candidate, we require `xform_self_ty` to be
|
||||
@ -799,7 +799,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
// the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error
|
||||
// will be reported by `object_safety.rs` if the method refers to the
|
||||
// `Self` type anywhere other than the receiver. Here, we use a
|
||||
// substitution that replaces `Self` with the object type itself. Hence,
|
||||
// instantiation that replaces `Self` with the object type itself. Hence,
|
||||
// a `&self` method will wind up with an argument type like `&dyn Trait`.
|
||||
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
|
||||
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
|
||||
@ -1857,8 +1857,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
assert!(!args.has_escaping_bound_vars());
|
||||
|
||||
// It is possible for type parameters or early-bound lifetimes
|
||||
// to appear in the signature of `self`. The substitutions we
|
||||
// are given do not include type/lifetime parameters for the
|
||||
// to appear in the signature of `self`. The generic parameters
|
||||
// we are given do not include type/lifetime parameters for the
|
||||
// method yet. So create fresh variables here for those too,
|
||||
// if there are any.
|
||||
let generics = self.tcx.generics_of(method);
|
||||
@ -1889,7 +1889,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
self.instantiate_bound_regions_with_erased(xform_fn_sig)
|
||||
}
|
||||
|
||||
/// Gets the type of an impl and generate substitutions with inference vars.
|
||||
/// Gets the type of an impl and generate generic parameters with inference vars.
|
||||
fn impl_ty_and_args(
|
||||
&self,
|
||||
impl_def_id: DefId,
|
||||
@ -1913,7 +1913,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
/// late-bound regions with 'static. Otherwise, if we were going to replace late-bound
|
||||
/// regions with actual region variables as is proper, we'd have to ensure that the same
|
||||
/// region got replaced with the same variable, which requires a bit more coordination
|
||||
/// and/or tracking the substitution and
|
||||
/// and/or tracking the instantiations and
|
||||
/// so forth.
|
||||
fn instantiate_bound_regions_with_erased<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||
where
|
||||
|
@ -357,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PlaceOp::Deref => None,
|
||||
PlaceOp::Index => {
|
||||
// We would need to recover the `T` used when we resolve `<_ as Index<T>>::index`
|
||||
// in try_index_step. This is the subst at index 1.
|
||||
// in try_index_step. This is the arg at index 1.
|
||||
//
|
||||
// Note: we should *not* use `expr_ty` of index_expr here because autoderef
|
||||
// during coercions can cause type of index_expr to differ from `T` (#72002).
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Type resolution: the phase that finds all the types in the AST with
|
||||
// unresolved type variables and replaces "ty_var" types with their
|
||||
// substitutions.
|
||||
// generic parameters.
|
||||
|
||||
use crate::FnCtxt;
|
||||
use rustc_data_structures::unord::ExtendUnord;
|
||||
@ -621,7 +621,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
self.write_ty_to_typeck_results(hir_id, n_ty);
|
||||
debug!(?n_ty);
|
||||
|
||||
// Resolve any substitutions
|
||||
// Resolve any generic parameters
|
||||
if let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(hir_id) {
|
||||
let args = self.resolve(args, &span);
|
||||
debug!("write_args_to_tcx({:?}, {:?})", hir_id, args);
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! This module contains code to substitute new values into a
|
||||
//! This module contains code to instantiate new values into a
|
||||
//! `Canonical<'tcx, T>`.
|
||||
//!
|
||||
//! For an overview of what canonicalization is and how it fits into
|
||||
@ -16,17 +16,17 @@ use rustc_middle::ty::{self, TyCtxt};
|
||||
pub trait CanonicalExt<'tcx, V> {
|
||||
/// Instantiate the wrapped value, replacing each canonical value
|
||||
/// with the value given in `var_values`.
|
||||
fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>;
|
||||
|
||||
/// Allows one to apply a substitute to some subset of
|
||||
/// Allows one to apply a instantiation to some subset of
|
||||
/// `self.value`. Invoke `projection_fn` with `self.value` to get
|
||||
/// a value V that is expressed in terms of the same canonical
|
||||
/// variables bound in `self` (usually this extracts from subset
|
||||
/// of `self`). Apply the substitution `var_values` to this value
|
||||
/// of `self`). Apply the instantiation `var_values` to this value
|
||||
/// V, replacing each of the canonical variables.
|
||||
fn substitute_projected<T>(
|
||||
fn instantiate_projected<T>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
var_values: &CanonicalVarValues<'tcx>,
|
||||
@ -37,14 +37,14 @@ pub trait CanonicalExt<'tcx, V> {
|
||||
}
|
||||
|
||||
impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
|
||||
fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.substitute_projected(tcx, var_values, |value| value.clone())
|
||||
self.instantiate_projected(tcx, var_values, |value| value.clone())
|
||||
}
|
||||
|
||||
fn substitute_projected<T>(
|
||||
fn instantiate_projected<T>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
var_values: &CanonicalVarValues<'tcx>,
|
||||
@ -55,14 +55,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
|
||||
{
|
||||
assert_eq!(self.variables.len(), var_values.len());
|
||||
let value = projection_fn(&self.value);
|
||||
substitute_value(tcx, var_values, value)
|
||||
instantiate_value(tcx, var_values, value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Substitute the values from `var_values` into `value`. `var_values`
|
||||
/// Instantiate the values from `var_values` into `value`. `var_values`
|
||||
/// must be values for the set of canonical variables that appear in
|
||||
/// `value`.
|
||||
pub(super) fn substitute_value<'tcx, T>(
|
||||
pub(super) fn instantiate_value<'tcx, T>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
var_values: &CanonicalVarValues<'tcx>,
|
||||
value: T,
|
@ -30,24 +30,24 @@ use rustc_middle::ty::GenericArg;
|
||||
use rustc_middle::ty::{self, List, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub use instantiate::CanonicalExt;
|
||||
pub use rustc_middle::infer::canonical::*;
|
||||
pub use substitute::CanonicalExt;
|
||||
|
||||
mod canonicalizer;
|
||||
mod instantiate;
|
||||
pub mod query_response;
|
||||
mod substitute;
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Creates a substitution S for the canonical value with fresh
|
||||
/// Creates an instantiation S for the canonical value with fresh
|
||||
/// inference variables and applies it to the canonical value.
|
||||
/// Returns both the instantiated result *and* the substitution S.
|
||||
/// Returns both the instantiated result *and* the instantiation S.
|
||||
///
|
||||
/// This can be invoked as part of constructing an
|
||||
/// inference context at the start of a query (see
|
||||
/// `InferCtxtBuilder::build_with_canonical`). It basically
|
||||
/// brings the canonical value "into scope" within your new infcx.
|
||||
///
|
||||
/// At the end of processing, the substitution S (once
|
||||
/// At the end of processing, the instantiation S (once
|
||||
/// canonicalized) then represents the values that you computed
|
||||
/// for each of the canonical inputs to your query.
|
||||
pub fn instantiate_canonical_with_fresh_inference_vars<T>(
|
||||
@ -73,14 +73,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
let canonical_inference_vars =
|
||||
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
|
||||
let result = canonical.substitute(self.tcx, &canonical_inference_vars);
|
||||
let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
|
||||
(result, canonical_inference_vars)
|
||||
}
|
||||
|
||||
/// Given the "infos" about the canonical variables from some
|
||||
/// canonical, creates fresh variables with the same
|
||||
/// characteristics (see `instantiate_canonical_var` for
|
||||
/// details). You can then use `substitute` to instantiate the
|
||||
/// details). You can then use `instantiate` to instantiate the
|
||||
/// canonical variable with these inference variables.
|
||||
fn instantiate_canonical_vars(
|
||||
&self,
|
||||
|
@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||
|
||||
use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
|
||||
use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt};
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
|
||||
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
|
||||
@ -189,18 +189,18 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
where
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let InferOk { value: result_subst, mut obligations } =
|
||||
self.query_response_substitution(cause, param_env, original_values, query_response)?;
|
||||
let InferOk { value: result_args, mut obligations } =
|
||||
self.query_response_instantiation(cause, param_env, original_values, query_response)?;
|
||||
|
||||
obligations.extend(self.query_outlives_constraints_into_obligations(
|
||||
cause,
|
||||
param_env,
|
||||
&query_response.value.region_constraints.outlives,
|
||||
&result_subst,
|
||||
&result_args,
|
||||
));
|
||||
|
||||
let user_result: R =
|
||||
query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
|
||||
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
|
||||
|
||||
Ok(InferOk { value: user_result, obligations })
|
||||
}
|
||||
@ -225,11 +225,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// basic operations as `instantiate_query_response_and_region_obligations` but
|
||||
/// it returns its result differently:
|
||||
///
|
||||
/// - It creates a substitution `S` that maps from the original
|
||||
/// - It creates an instantiation `S` that maps from the original
|
||||
/// query variables to the values computed in the query
|
||||
/// result. If any errors arise, they are propagated back as an
|
||||
/// `Err` result.
|
||||
/// - In the case of a successful substitution, we will append
|
||||
/// - In the case of a successful instantiation, we will append
|
||||
/// `QueryOutlivesConstraint` values onto the
|
||||
/// `output_query_region_constraints` vector for the solver to
|
||||
/// use (if an error arises, some values may also be pushed, but
|
||||
@ -239,7 +239,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// that must be processed. In this case, those subobligations
|
||||
/// are propagated back in the return value.
|
||||
/// - Finally, the query result (of type `R`) is propagated back,
|
||||
/// after applying the substitution `S`.
|
||||
/// after applying the instantiation `S`.
|
||||
pub fn instantiate_nll_query_response_and_region_obligations<R>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
@ -251,8 +251,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
where
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let InferOk { value: result_subst, mut obligations } = self
|
||||
.query_response_substitution_guess(cause, param_env, original_values, query_response)?;
|
||||
let InferOk { value: result_args, mut obligations } = self
|
||||
.query_response_instantiation_guess(
|
||||
cause,
|
||||
param_env,
|
||||
original_values,
|
||||
query_response,
|
||||
)?;
|
||||
|
||||
// Compute `QueryOutlivesConstraint` values that unify each of
|
||||
// the original values `v_o` that was canonicalized into a
|
||||
@ -262,7 +267,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
for (index, original_value) in original_values.var_values.iter().enumerate() {
|
||||
// ...with the value `v_r` of that variable from the query.
|
||||
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
|
||||
let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
|
||||
v.var_values[BoundVar::new(index)]
|
||||
});
|
||||
match (original_value.unpack(), result_value.unpack()) {
|
||||
@ -321,7 +326,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// ...also include the other query region constraints from the query.
|
||||
output_query_region_constraints.outlives.extend(
|
||||
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
|
||||
let r_c = substitute_value(self.tcx, &result_subst, r_c);
|
||||
let r_c = instantiate_value(self.tcx, &result_args, r_c);
|
||||
|
||||
// Screen out `'a: 'a` cases.
|
||||
let ty::OutlivesPredicate(k1, r2) = r_c.0;
|
||||
@ -336,26 +341,26 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
.region_constraints
|
||||
.member_constraints
|
||||
.iter()
|
||||
.map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())),
|
||||
.map(|p_c| instantiate_value(self.tcx, &result_args, p_c.clone())),
|
||||
);
|
||||
|
||||
let user_result: R =
|
||||
query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
|
||||
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
|
||||
|
||||
Ok(InferOk { value: user_result, obligations })
|
||||
}
|
||||
|
||||
/// Given the original values and the (canonicalized) result from
|
||||
/// computing a query, returns a substitution that can be applied
|
||||
/// computing a query, returns an instantiation that can be applied
|
||||
/// to the query result to convert the result back into the
|
||||
/// original namespace.
|
||||
///
|
||||
/// The substitution also comes accompanied with subobligations
|
||||
/// The instantiation also comes accompanied with subobligations
|
||||
/// that arose from unification; these might occur if (for
|
||||
/// example) we are doing lazy normalization and the value
|
||||
/// assigned to a type variable is unified with an unnormalized
|
||||
/// projection.
|
||||
fn query_response_substitution<R>(
|
||||
fn query_response_instantiation<R>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -366,11 +371,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
debug!(
|
||||
"query_response_substitution(original_values={:#?}, query_response={:#?})",
|
||||
"query_response_instantiation(original_values={:#?}, query_response={:#?})",
|
||||
original_values, query_response,
|
||||
);
|
||||
|
||||
let mut value = self.query_response_substitution_guess(
|
||||
let mut value = self.query_response_instantiation_guess(
|
||||
cause,
|
||||
param_env,
|
||||
original_values,
|
||||
@ -378,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
)?;
|
||||
|
||||
value.obligations.extend(
|
||||
self.unify_query_response_substitution_guess(
|
||||
self.unify_query_response_instantiation_guess(
|
||||
cause,
|
||||
param_env,
|
||||
original_values,
|
||||
@ -392,7 +397,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
|
||||
/// Given the original values and the (canonicalized) result from
|
||||
/// computing a query, returns a **guess** at a substitution that
|
||||
/// computing a query, returns a **guess** at an instantiation that
|
||||
/// can be applied to the query result to convert the result back
|
||||
/// into the original namespace. This is called a **guess**
|
||||
/// because it uses a quick heuristic to find the values for each
|
||||
@ -401,7 +406,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// variable instead. Therefore, the result of this method must be
|
||||
/// properly unified
|
||||
#[instrument(level = "debug", skip(self, cause, param_env))]
|
||||
fn query_response_substitution_guess<R>(
|
||||
fn query_response_instantiation_guess<R>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -450,7 +455,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
if let ty::Bound(debruijn, b) = *result_value.kind() {
|
||||
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
|
||||
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
}
|
||||
@ -460,7 +465,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
if let ty::ReBound(debruijn, br) = *result_value {
|
||||
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
|
||||
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[br.var] = Some(*original_value);
|
||||
}
|
||||
@ -469,7 +474,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
|
||||
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
|
||||
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b] = Some(*original_value);
|
||||
}
|
||||
@ -477,10 +482,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Create a result substitution: if we found a value for a
|
||||
// Create result arguments: if we found a value for a
|
||||
// given variable in the loop above, use that. Otherwise, use
|
||||
// a fresh inference variable.
|
||||
let result_subst = CanonicalVarValues {
|
||||
let result_args = CanonicalVarValues {
|
||||
var_values: self.tcx.mk_args_from_iter(
|
||||
query_response.variables.iter().enumerate().map(|(index, info)| {
|
||||
if info.universe() != ty::UniverseIndex::ROOT {
|
||||
@ -511,8 +516,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
// Carry all newly resolved opaque types to the caller's scope
|
||||
for &(a, b) in &query_response.value.opaque_types {
|
||||
let a = substitute_value(self.tcx, &result_subst, a);
|
||||
let b = substitute_value(self.tcx, &result_subst, b);
|
||||
let a = instantiate_value(self.tcx, &result_args, a);
|
||||
let b = instantiate_value(self.tcx, &result_args, b);
|
||||
debug!(?a, ?b, "constrain opaque type");
|
||||
// We use equate here instead of, for example, just registering the
|
||||
// opaque type's hidden value directly, because we may be instantiating
|
||||
@ -532,7 +537,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
Ok(InferOk { value: result_subst, obligations })
|
||||
Ok(InferOk { value: result_args, obligations })
|
||||
}
|
||||
|
||||
/// Given a "guess" at the values for the canonical variables in
|
||||
@ -540,13 +545,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// query result. Often, but not always, this is a no-op, because
|
||||
/// we already found the mapping in the "guessing" step.
|
||||
///
|
||||
/// See also: `query_response_substitution_guess`
|
||||
fn unify_query_response_substitution_guess<R>(
|
||||
/// See also: [`Self::query_response_instantiation_guess`]
|
||||
fn unify_query_response_instantiation_guess<R>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: &OriginalQueryValues<'tcx>,
|
||||
result_subst: &CanonicalVarValues<'tcx>,
|
||||
result_args: &CanonicalVarValues<'tcx>,
|
||||
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
|
||||
) -> InferResult<'tcx, ()>
|
||||
where
|
||||
@ -554,15 +559,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
{
|
||||
// A closure that yields the result value for the given
|
||||
// canonical variable; this is taken from
|
||||
// `query_response.var_values` after applying the substitution
|
||||
// `result_subst`.
|
||||
let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> {
|
||||
query_response.substitute_projected(self.tcx, result_subst, |v| v.var_values[index])
|
||||
// `query_response.var_values` after applying the instantiation
|
||||
// by `result_args`.
|
||||
let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> {
|
||||
query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index])
|
||||
};
|
||||
|
||||
// Unify the original value for each variable with the value
|
||||
// taken from `query_response` (after applying `result_subst`).
|
||||
self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
|
||||
// taken from `query_response` (after applying `result_args`).
|
||||
self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response)
|
||||
}
|
||||
|
||||
/// Converts the region constraints resulting from a query into an
|
||||
@ -571,11 +576,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
&'a self,
|
||||
cause: &'a ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
|
||||
result_subst: &'a CanonicalVarValues<'tcx>,
|
||||
uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
|
||||
result_args: &'a CanonicalVarValues<'tcx>,
|
||||
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
|
||||
unsubstituted_region_constraints.iter().map(move |&constraint| {
|
||||
let predicate = substitute_value(self.tcx, result_subst, constraint);
|
||||
uninstantiated_region_constraints.iter().map(move |&constraint| {
|
||||
let predicate = instantiate_value(self.tcx, result_args, constraint);
|
||||
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
|
||||
})
|
||||
}
|
||||
|
@ -679,7 +679,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
/// inference context that contains each of the bound values
|
||||
/// within instantiated as a fresh variable. The `f` closure is
|
||||
/// invoked with the new infcx, along with the instantiated value
|
||||
/// `V` and a substitution `S`. This substitution `S` maps from
|
||||
/// `V` and a instantiation `S`. This instantiation `S` maps from
|
||||
/// the bound values in `C` to their instantiated values in `V`
|
||||
/// (in other words, `S(C) = V`).
|
||||
pub fn build_with_canonical<T>(
|
||||
@ -691,8 +691,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let infcx = self.build();
|
||||
let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
|
||||
(infcx, value, subst)
|
||||
let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
|
||||
(infcx, value, args)
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> InferCtxt<'tcx> {
|
||||
@ -1194,13 +1194,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
// Create a type inference variable for the given
|
||||
// type parameter definition. The substitutions are
|
||||
// type parameter definition. The generic parameters are
|
||||
// for actual parameters that may be referred to by
|
||||
// the default of this type parameter, if it exists.
|
||||
// e.g., `struct Foo<A, B, C = (A, B)>(...);` when
|
||||
// used in a path such as `Foo::<T, U>::new()` will
|
||||
// use an inference variable for `C` with `[T, U]`
|
||||
// as the substitutions for the default, `(T, U)`.
|
||||
// as the generic parameters for the default, `(T, U)`.
|
||||
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
|
||||
self.universe(),
|
||||
TypeVariableOrigin {
|
||||
@ -1256,7 +1256,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
|
||||
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping each
|
||||
/// type/region parameter to a fresh inference variable.
|
||||
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
|
||||
GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
|
||||
@ -1411,7 +1411,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
if !value.has_infer() {
|
||||
return value; // Avoid duplicated subst-folding.
|
||||
return value; // Avoid duplicated type-folding.
|
||||
}
|
||||
let mut r = InferenceLiteralEraser { tcx: self.tcx };
|
||||
value.fold_with(&mut r)
|
||||
@ -1458,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// Instantiates the bound variables in a given binder with fresh inference
|
||||
// variables in the current universe.
|
||||
//
|
||||
// Use this method if you'd like to find some substitution of the binder's
|
||||
// Use this method if you'd like to find some generic parameters of the binder's
|
||||
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
|
||||
// that corresponds to your use case, consider whether or not you should
|
||||
// use [`InferCtxt::enter_forall`] instead.
|
||||
@ -1603,10 +1603,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Resolves and evaluates a constant.
|
||||
///
|
||||
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
|
||||
/// substitutions and environment are used to resolve the constant. Alternatively if the
|
||||
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
|
||||
/// generic parameters and environment are used to resolve the constant. Alternatively if the
|
||||
/// constant has generic parameters in scope the instantiations are used to evaluate the value of
|
||||
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
|
||||
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
|
||||
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still
|
||||
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
|
||||
/// returned.
|
||||
///
|
||||
@ -1652,7 +1652,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
|
||||
|
||||
// The return value is the evaluated value which doesn't contain any reference to inference
|
||||
// variables, thus we don't need to substitute back the original values.
|
||||
// variables, thus we don't need to instantiate back the original values.
|
||||
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// ```
|
||||
///
|
||||
/// As indicating in the comments above, each of those references
|
||||
/// is (in the compiler) basically a substitution (`args`)
|
||||
/// is (in the compiler) basically generic paramters (`args`)
|
||||
/// applied to the type of a suitable `def_id` (which identifies
|
||||
/// `Foo1` or `Foo2`).
|
||||
///
|
||||
|
@ -25,7 +25,7 @@ use crate::infer::region_constraints::VerifyIfEq;
|
||||
/// * `None` if `some_type` cannot be made equal to `test_ty`,
|
||||
/// no matter the values of the variables in `exists`.
|
||||
/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
|
||||
/// any bound existential variables, which will be substituted) for the
|
||||
/// any bound existential variables, which will be instantiated) for the
|
||||
/// type under test.
|
||||
///
|
||||
/// NB: This function uses a simplistic, syntactic version of type equality.
|
||||
@ -59,7 +59,7 @@ pub fn extract_verify_if_eq<'tcx>(
|
||||
}
|
||||
} else {
|
||||
// The region does not contain any bound variables, so we don't need
|
||||
// to do any substitution.
|
||||
// to do any instantiation.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
@ -277,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the `DefId` of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// `'a`. You could then apply the instantiations from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
|
||||
/// the trait. In fact, it works by searching for just such a
|
||||
|
@ -183,14 +183,14 @@ where
|
||||
fn relate_item_args(
|
||||
&mut self,
|
||||
item_def_id: DefId,
|
||||
a_subst: ty::GenericArgsRef<'tcx>,
|
||||
b_subst: ty::GenericArgsRef<'tcx>,
|
||||
a_arg: ty::GenericArgsRef<'tcx>,
|
||||
b_arg: ty::GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
|
||||
if self.ambient_variance == ty::Variance::Invariant {
|
||||
// Avoid fetching the variance if we are in an invariant
|
||||
// context; no need, and it can induce dependency cycles
|
||||
// (e.g., #41849).
|
||||
relate::relate_args_invariantly(self, a_subst, b_subst)
|
||||
relate::relate_args_invariantly(self, a_arg, b_arg)
|
||||
} else {
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
@ -198,8 +198,8 @@ where
|
||||
self,
|
||||
item_def_id,
|
||||
opt_variances,
|
||||
a_subst,
|
||||
b_subst,
|
||||
a_arg,
|
||||
b_arg,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ pub enum TypeVariableOriginKind {
|
||||
AdjustmentType,
|
||||
|
||||
/// In type check, when we are type checking a function that
|
||||
/// returns `-> dyn Foo`, we substitute a type variable for the
|
||||
/// returns `-> dyn Foo`, we instantiate a type variable with the
|
||||
/// return type for diagnostic purposes.
|
||||
DynReturnFn,
|
||||
LatticeVariable,
|
||||
|
@ -285,7 +285,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
||||
let obligations =
|
||||
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
|
||||
elaboratable.child_with_derived_cause(
|
||||
clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
|
||||
clause
|
||||
.instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
|
||||
span,
|
||||
bound_clause.rebind(data),
|
||||
index,
|
||||
|
@ -319,6 +319,11 @@ lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not
|
||||
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_invalid_reference_casting_bigger_layout = casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
.label = casting happend here
|
||||
.alloc = backing allocation comes from here
|
||||
.layout = casting from `{$from_ty}` ({$from_size} bytes) to `{$to_ty}` ({$to_size} bytes)
|
||||
|
||||
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
|
@ -716,7 +716,7 @@ pub enum InvalidFromUtf8Diag {
|
||||
|
||||
// reference_casting.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum InvalidReferenceCastingDiag {
|
||||
pub enum InvalidReferenceCastingDiag<'tcx> {
|
||||
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||
#[note(lint_invalid_reference_casting_note_book)]
|
||||
BorrowAsMut {
|
||||
@ -733,6 +733,18 @@ pub enum InvalidReferenceCastingDiag {
|
||||
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
|
||||
ty_has_interior_mutability: Option<()>,
|
||||
},
|
||||
#[diag(lint_invalid_reference_casting_bigger_layout)]
|
||||
#[note(lint_layout)]
|
||||
BiggerLayout {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
#[label(lint_alloc)]
|
||||
alloc: Span,
|
||||
from_ty: Ty<'tcx>,
|
||||
from_size: u64,
|
||||
to_ty: Ty<'tcx>,
|
||||
to_size: u64,
|
||||
},
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
|
@ -1,6 +1,7 @@
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use rustc_middle::ty::{self, TypeAndMut};
|
||||
use rustc_middle::ty::layout::LayoutOf as _;
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, TypeAndMut};
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
|
||||
@ -38,13 +39,19 @@ declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
|
||||
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if let Some((e, pat)) = borrow_or_assign(cx, expr) {
|
||||
if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) {
|
||||
let init = cx.expr_or_init(e);
|
||||
let init = cx.expr_or_init(e);
|
||||
let orig_cast = if init.span != e.span { Some(init.span) } else { None };
|
||||
|
||||
let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) else {
|
||||
return;
|
||||
};
|
||||
let orig_cast = if init.span != e.span { Some(init.span) } else { None };
|
||||
// small cache to avoid recomputing needlesly computing peel_casts of init
|
||||
let mut peel_casts = {
|
||||
let mut peel_casts_cache = None;
|
||||
move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init))
|
||||
};
|
||||
|
||||
if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign)
|
||||
&& let Some(ty_has_interior_mutability) =
|
||||
is_cast_from_ref_to_mut_ptr(cx, init, &mut peel_casts)
|
||||
{
|
||||
let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
|
||||
|
||||
cx.emit_span_lint(
|
||||
@ -63,6 +70,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((from_ty_layout, to_ty_layout, e_alloc)) =
|
||||
is_cast_to_bigger_memory_layout(cx, init, &mut peel_casts)
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
INVALID_REFERENCE_CASTING,
|
||||
expr.span,
|
||||
InvalidReferenceCastingDiag::BiggerLayout {
|
||||
orig_cast,
|
||||
alloc: e_alloc.span,
|
||||
from_ty: from_ty_layout.ty,
|
||||
from_size: from_ty_layout.layout.size().bytes(),
|
||||
to_ty: to_ty_layout.ty,
|
||||
to_size: to_ty_layout.layout.size().bytes(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,6 +148,7 @@ fn borrow_or_assign<'tcx>(
|
||||
fn is_cast_from_ref_to_mut_ptr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
orig_expr: &'tcx Expr<'tcx>,
|
||||
mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool),
|
||||
) -> Option<bool> {
|
||||
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
|
||||
|
||||
@ -132,7 +157,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
|
||||
return None;
|
||||
}
|
||||
|
||||
let (e, need_check_freeze) = peel_casts(cx, orig_expr);
|
||||
let (e, need_check_freeze) = peel_casts();
|
||||
|
||||
let start_ty = cx.typeck_results().node_type(e.hir_id);
|
||||
if let ty::Ref(_, inner_ty, Mutability::Not) = start_ty.kind() {
|
||||
@ -151,6 +176,49 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_cast_to_bigger_memory_layout<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
orig_expr: &'tcx Expr<'tcx>,
|
||||
mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool),
|
||||
) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> {
|
||||
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
|
||||
|
||||
let ty::RawPtr(TypeAndMut { ty: inner_end_ty, mutbl: _ }) = end_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let (e, _) = peel_casts();
|
||||
let start_ty = cx.typeck_results().node_type(e.hir_id);
|
||||
|
||||
let ty::Ref(_, inner_start_ty, _) = start_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// try to find the underlying allocation
|
||||
let e_alloc = cx.expr_or_init(e);
|
||||
let e_alloc =
|
||||
if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc };
|
||||
let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id);
|
||||
|
||||
// if we do not find it we bail out, as this may not be UB
|
||||
// see https://github.com/rust-lang/unsafe-code-guidelines/issues/256
|
||||
if alloc_ty.is_any_ptr() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let from_layout = cx.layout_of(*inner_start_ty).ok()?;
|
||||
let alloc_layout = cx.layout_of(alloc_ty).ok()?;
|
||||
let to_layout = cx.layout_of(*inner_end_ty).ok()?;
|
||||
|
||||
if to_layout.layout.size() > from_layout.layout.size()
|
||||
&& to_layout.layout.size() > alloc_layout.layout.size()
|
||||
{
|
||||
Some((from_layout, to_layout, *e_alloc))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
|
||||
let mut gone_trough_unsafe_cell_raw_get = false;
|
||||
|
||||
|
@ -53,7 +53,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
|
||||
|
||||
/// A set of values corresponding to the canonical variables from some
|
||||
/// `Canonical`. You can give these values to
|
||||
/// `canonical_value.substitute` to substitute them into the canonical
|
||||
/// `canonical_value.instantiate` to instantiate them into the canonical
|
||||
/// value at the right places.
|
||||
///
|
||||
/// When you canonicalize a value `V`, you get back one of these
|
||||
|
@ -11,13 +11,13 @@ use rustc_session::lint;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
|
||||
// In some situations def_id will have substitutions within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self, def_id);
|
||||
@ -29,10 +29,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Resolves and evaluates a constant.
|
||||
///
|
||||
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
|
||||
/// substitutions and environment are used to resolve the constant. Alternatively if the
|
||||
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
|
||||
/// generic parameters and environment are used to resolve the constant. Alternatively if the
|
||||
/// constant has generic parameters in scope the generic parameters are used to evaluate the value of
|
||||
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
|
||||
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
|
||||
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still
|
||||
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
|
||||
/// returned.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -214,13 +214,13 @@ impl<'tcx> TyCtxtAt<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) {
|
||||
// In some situations def_id will have substitutions within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self.tcx, def_id);
|
||||
|
@ -186,7 +186,7 @@ impl<'tcx> MonoItem<'tcx> {
|
||||
MonoItem::GlobalAsm(..) => return true,
|
||||
};
|
||||
|
||||
!tcx.subst_and_check_impossible_predicates((def_id, &args))
|
||||
!tcx.instantiate_and_check_impossible_predicates((def_id, &args))
|
||||
}
|
||||
|
||||
pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
|
||||
|
@ -491,7 +491,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
|
||||
let kind = tcx.def_kind(def_id);
|
||||
let is_function = match kind {
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
|
||||
_ => tcx.is_closure_or_coroutine(def_id),
|
||||
_ => tcx.is_closure_like(def_id),
|
||||
};
|
||||
match (kind, body.source.promoted) {
|
||||
(_, Some(i)) => write!(w, "{i:?} in ")?,
|
||||
|
@ -2078,9 +2078,9 @@ rustc_queries! {
|
||||
desc { "normalizing `{:?}`", goal.value.value.value }
|
||||
}
|
||||
|
||||
query subst_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool {
|
||||
query instantiate_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool {
|
||||
desc { |tcx|
|
||||
"checking impossible substituted predicates: `{}`",
|
||||
"checking impossible instantiated predicates: `{}`",
|
||||
tcx.def_path_str(key.0)
|
||||
}
|
||||
}
|
||||
|
@ -721,7 +721,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||
}
|
||||
|
||||
/// Identifies a particular impl in the source, along with a set of
|
||||
/// substitutions from the impl's type/lifetime parameters. The
|
||||
/// generic parameters from the impl's type/lifetime parameters. The
|
||||
/// `nested` vector corresponds to the nested obligations attached to
|
||||
/// the impl's type parameters.
|
||||
///
|
||||
|
@ -49,7 +49,8 @@ pub type EvaluationCache<'tcx> = Cache<
|
||||
/// parameters don't unify with regular types, but they *can* unify
|
||||
/// with variables from blanket impls, and (unless we know its bounds
|
||||
/// will always be satisfied) picking the blanket impl will be wrong
|
||||
/// for at least *some* substitutions. To make this concrete, if we have
|
||||
/// for at least *some* generic parameters. To make this concrete, if
|
||||
/// we have
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// trait AsDebug { type Out: fmt::Debug; fn debug(self) -> Self::Out; }
|
||||
|
@ -37,7 +37,7 @@ impl<'tcx> Elaborator<'tcx> {
|
||||
let super_predicates =
|
||||
self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map(
|
||||
|&(pred, _)| {
|
||||
let clause = pred.subst_supertrait(self.tcx, &trait_ref);
|
||||
let clause = pred.instantiate_supertrait(self.tcx, &trait_ref);
|
||||
self.visited.insert(clause).then_some(clause)
|
||||
},
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use crate::ty::{self, InferConst, Ty, TyCtxt};
|
||||
|
||||
/// A type "A" *matches* "B" if the fresh types in B could be
|
||||
/// substituted with values so as to make it equal to A. Matching is
|
||||
/// instantiated with values so as to make it equal to A. Matching is
|
||||
/// intended to be used only on freshened types, and it basically
|
||||
/// indicates if the non-freshened versions of A and B could have been
|
||||
/// unified.
|
||||
|
@ -197,7 +197,7 @@ pub struct ClosureTypeInfo<'tcx> {
|
||||
}
|
||||
|
||||
fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> {
|
||||
debug_assert!(tcx.is_closure_or_coroutine(def.to_def_id()));
|
||||
debug_assert!(tcx.is_closure_like(def.to_def_id()));
|
||||
let typeck_results = tcx.typeck(def);
|
||||
let user_provided_sig = typeck_results.user_provided_sigs[&def];
|
||||
let captures = typeck_results.closure_min_captures_flattened(def);
|
||||
@ -217,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
|
||||
if !self.is_closure_or_coroutine(def_id.to_def_id()) {
|
||||
if !self.is_closure_like(def_id.to_def_id()) {
|
||||
return &[];
|
||||
};
|
||||
self.closure_typeinfo(def_id).captures
|
||||
|
@ -235,7 +235,7 @@ impl<'tcx> Const<'tcx> {
|
||||
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
|
||||
// does not provide the parents generics to anonymous constants. We still allow generic const
|
||||
// parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
|
||||
// ever try to substitute the generic parameters in their bodies.
|
||||
// ever try to instantiate the generic parameters in their bodies.
|
||||
match expr.kind {
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
|
@ -418,10 +418,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
// Shifter
|
||||
//
|
||||
// Shifts the De Bruijn indices on all escaping bound vars by a
|
||||
// fixed amount. Useful in substitution or when otherwise introducing
|
||||
// fixed amount. Useful in instantiation or when otherwise introducing
|
||||
// a binding level that is not intended to capture the existing bound
|
||||
// vars. See comment on `shift_vars_through_binders` method in
|
||||
// `subst.rs` for more details.
|
||||
// `rustc_middle/src/ty/generic_args.rs` for more details.
|
||||
|
||||
struct Shifter<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -803,13 +803,13 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The actual substitution engine itself is a type folder.
|
||||
// The actual instantiation engine itself is a type folder.
|
||||
|
||||
struct ArgFolder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'a [GenericArg<'tcx>],
|
||||
|
||||
/// Number of region binders we have passed through while doing the substitution
|
||||
/// Number of region binders we have passed through while doing the instantiation
|
||||
binders_passed: u32,
|
||||
}
|
||||
|
||||
@ -834,7 +834,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'a, 'tcx> {
|
||||
#[inline(never)]
|
||||
fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! {
|
||||
bug!(
|
||||
"Region parameter out of range when substituting in region {} (index={}, args = {:?})",
|
||||
"Region parameter out of range when instantiating in region {} (index={}, args = {:?})",
|
||||
data.name,
|
||||
data.index,
|
||||
args,
|
||||
@ -845,7 +845,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'a, 'tcx> {
|
||||
#[inline(never)]
|
||||
fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! {
|
||||
bug!(
|
||||
"Unexpected parameter {:?} when substituting in region {} (index={})",
|
||||
"Unexpected parameter {:?} when instantiating in region {} (index={})",
|
||||
other,
|
||||
data.name,
|
||||
data.index
|
||||
@ -854,7 +854,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'a, 'tcx> {
|
||||
|
||||
// Note: This routine only handles regions that are bound on
|
||||
// type declarations and other outer declarations, not those
|
||||
// bound in *fn types*. Region substitution of the bound
|
||||
// bound in *fn types*. Region instantiation of the bound
|
||||
// regions that appear in a function signature is done using
|
||||
// the specialized routine `ty::replace_late_regions()`.
|
||||
match *r {
|
||||
@ -913,7 +913,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
#[inline(never)]
|
||||
fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
|
||||
bug!(
|
||||
"expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, args={:?}",
|
||||
"expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index,
|
||||
@ -926,7 +926,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
#[inline(never)]
|
||||
fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
|
||||
bug!(
|
||||
"type parameter `{:?}` ({:?}/{}) out of range when substituting, args={:?}",
|
||||
"type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index,
|
||||
@ -955,7 +955,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
kind: GenericArgKind<'tcx>,
|
||||
) -> ! {
|
||||
bug!(
|
||||
"expected const for `{:?}` ({:?}/{}) but found {:?} when substituting args={:?}",
|
||||
"expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index,
|
||||
@ -968,7 +968,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
#[inline(never)]
|
||||
fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
|
||||
bug!(
|
||||
"const parameter `{:?}` ({:?}/{}) out of range when substituting args={:?}",
|
||||
"const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index,
|
||||
@ -976,8 +976,8 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
/// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
|
||||
/// when we are substituting a type with escaping bound vars into a context where we have
|
||||
/// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs
|
||||
/// when we are instantating a type with escaping bound vars into a context where we have
|
||||
/// passed through binders. That's quite a mouthful. Let's see an example:
|
||||
///
|
||||
/// ```
|
||||
@ -997,7 +997,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
/// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
|
||||
/// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
|
||||
/// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
|
||||
/// De Bruijn index of 1. It's only during the substitution that we can see we must increase the
|
||||
/// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the
|
||||
/// depth by 1 to account for the binder that we passed through.
|
||||
///
|
||||
/// As a second example, consider this twist:
|
||||
@ -1015,7 +1015,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
/// // DebruijnIndex of 1 |
|
||||
/// // DebruijnIndex of 2
|
||||
/// ```
|
||||
/// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the
|
||||
/// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the
|
||||
/// first case we do not increase the De Bruijn index and in the second case we do. The reason
|
||||
/// is that only in the second case have we passed through a fn binder.
|
||||
fn shift_vars_through_binders<T: TypeFoldable<TyCtxt<'tcx>>>(&self, val: T) -> T {
|
||||
|
@ -125,7 +125,7 @@ pub struct GenericParamCount {
|
||||
/// Information about the formal type/lifetime parameters associated
|
||||
/// with an item or method. Analogous to `hir::Generics`.
|
||||
///
|
||||
/// The ordering of parameters is the same as in `Subst` (excluding child generics):
|
||||
/// The ordering of parameters is the same as in [`ty::GenericArg`] (excluding child generics):
|
||||
/// `Self` (optionally), `Lifetime` params..., `Type` params...
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct Generics {
|
||||
@ -140,7 +140,7 @@ pub struct Generics {
|
||||
pub has_self: bool,
|
||||
pub has_late_bound_regions: Option<Span>,
|
||||
|
||||
// The index of the host effect when substituted. (i.e. might be index to parent args)
|
||||
// The index of the host effect when instantiated. (i.e. might be index to parent args)
|
||||
pub host_effect_index: Option<usize>,
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ use std::fmt;
|
||||
///
|
||||
/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
|
||||
/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
|
||||
/// will do all required substitution as they run.
|
||||
/// will do all required instantiations as they run.
|
||||
///
|
||||
/// Note: the `Lift` impl is currently not used by rustc, but is used by
|
||||
/// rustc_codegen_cranelift when the `jit` feature is enabled.
|
||||
@ -138,7 +138,7 @@ pub enum InstanceDef<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> Instance<'tcx> {
|
||||
/// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and
|
||||
/// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and
|
||||
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
|
||||
pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
|
||||
let ty = tcx.type_of(self.def.def_id());
|
||||
@ -298,11 +298,11 @@ impl<'tcx> InstanceDef<'tcx> {
|
||||
}
|
||||
|
||||
/// Returns `true` when the MIR body associated with this instance should be monomorphized
|
||||
/// by its users (e.g. codegen or miri) by substituting the `args` from `Instance` (see
|
||||
/// by its users (e.g. codegen or miri) by instantiating the `args` from `Instance` (see
|
||||
/// `Instance::args_for_mir_body`).
|
||||
///
|
||||
/// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR
|
||||
/// body should perform necessary substitutions.
|
||||
/// body should perform necessary instantiations.
|
||||
pub fn has_polymorphic_mir_body(&self) -> bool {
|
||||
match *self {
|
||||
InstanceDef::CloneShim(..)
|
||||
@ -465,10 +465,7 @@ impl<'tcx> Instance<'tcx> {
|
||||
) -> Option<Instance<'tcx>> {
|
||||
debug!("resolve(def_id={:?}, args={:?})", def_id, args);
|
||||
// Use either `resolve_closure` or `resolve_for_vtable`
|
||||
assert!(
|
||||
!tcx.is_closure_or_coroutine(def_id),
|
||||
"Called `resolve_for_fn_ptr` on closure: {def_id:?}"
|
||||
);
|
||||
assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
|
||||
Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
|
||||
match resolved.def {
|
||||
InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
|
||||
@ -530,7 +527,7 @@ impl<'tcx> Instance<'tcx> {
|
||||
})
|
||||
)
|
||||
{
|
||||
if tcx.is_closure_or_coroutine(def) {
|
||||
if tcx.is_closure_like(def) {
|
||||
debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
|
||||
def, def_id, args);
|
||||
|
||||
@ -672,13 +669,13 @@ impl<'tcx> Instance<'tcx> {
|
||||
|
||||
/// Depending on the kind of `InstanceDef`, the MIR body associated with an
|
||||
/// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
|
||||
/// cases the MIR body is expressed in terms of the types found in the substitution array.
|
||||
/// In the former case, we want to substitute those generic types and replace them with the
|
||||
/// cases the MIR body is expressed in terms of the types found in the generic parameter array.
|
||||
/// In the former case, we want to instantiate those generic types and replace them with the
|
||||
/// values from the args when monomorphizing the function body. But in the latter case, we
|
||||
/// don't want to do that substitution, since it has already been done effectively.
|
||||
/// don't want to do that instantiation, since it has already been done effectively.
|
||||
///
|
||||
/// This function returns `Some(args)` in the former case and `None` otherwise -- i.e., if
|
||||
/// this function returns `None`, then the MIR body does not require substitution during
|
||||
/// this function returns `None`, then the MIR body does not require instantiation during
|
||||
/// codegen.
|
||||
fn args_for_mir_body(&self) -> Option<GenericArgsRef<'tcx>> {
|
||||
self.def.has_polymorphic_mir_body().then_some(self.args)
|
||||
|
@ -728,7 +728,7 @@ impl From<ty::ConstVid> for TermVid {
|
||||
/// the `GenericPredicates` are expressed in terms of the bound type
|
||||
/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance
|
||||
/// represented a set of bounds for some particular instantiation,
|
||||
/// meaning that the generic parameters have been substituted with
|
||||
/// meaning that the generic parameters have been instantiated with
|
||||
/// their values.
|
||||
///
|
||||
/// Example:
|
||||
@ -1672,7 +1672,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
|
||||
/// Returns the possibly-auto-generated MIR of a [`ty::InstanceDef`].
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
|
||||
match instance {
|
||||
|
@ -135,7 +135,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
/// Monomorphizes a type from the AST by first applying the
|
||||
/// in-scope substitutions and then normalizing any associated
|
||||
/// in-scope instantiations and then normalizing any associated
|
||||
/// types.
|
||||
/// Panics if normalization fails. In case normalization might fail
|
||||
/// use `try_instantiate_and_normalize_erasing_regions` instead.
|
||||
@ -149,12 +149,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let substituted = value.instantiate(self, param_args);
|
||||
self.normalize_erasing_regions(param_env, substituted)
|
||||
let instantiated = value.instantiate(self, param_args);
|
||||
self.normalize_erasing_regions(param_env, instantiated)
|
||||
}
|
||||
|
||||
/// Monomorphizes a type from the AST by first applying the
|
||||
/// in-scope substitutions and then trying to normalize any associated
|
||||
/// in-scope instantiations and then trying to normalize any associated
|
||||
/// types. Contrary to `instantiate_and_normalize_erasing_regions` this does
|
||||
/// not assume that normalization succeeds.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -167,8 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let substituted = value.instantiate(self, param_args);
|
||||
self.try_normalize_erasing_regions(param_env, substituted)
|
||||
let instantiated = value.instantiate(self, param_args);
|
||||
self.try_normalize_erasing_regions(param_env, instantiated)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,9 +164,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
|
||||
}
|
||||
|
||||
ty::Param(param) => {
|
||||
// Look it up in the substitution list.
|
||||
// Look it up in the generic parameters list.
|
||||
match self.map.get(&ty.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list; replace with the parameter from the
|
||||
// Found it in the generic parameters list; replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Type(t1)) => t1,
|
||||
Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
|
||||
@ -199,9 +199,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
|
||||
// Find a const parameter
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Param(..) => {
|
||||
// Look it up in the substitution list.
|
||||
// Look it up in the generic parameters list.
|
||||
match self.map.get(&ct.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list, replace with the parameter from the
|
||||
// Found it in the generic parameters list, replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Const(c1)) => c1,
|
||||
Some(u) => panic!("const mapped to unexpected kind: {u:?}"),
|
||||
|
@ -323,7 +323,7 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
/// and `U` as parameter 1.
|
||||
///
|
||||
/// Trait references also appear in object types like `Foo<U>`, but in
|
||||
/// that case the `Self` parameter is absent from the substitutions.
|
||||
/// that case the `Self` parameter is absent from the generic parameters.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct TraitRef<'tcx> {
|
||||
@ -406,7 +406,7 @@ impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> {
|
||||
/// ```ignore (illustrative)
|
||||
/// exists T. T: Trait<'a, 'b, X, Y>
|
||||
/// ```
|
||||
/// The substitutions don't include the erased `Self`, only trait
|
||||
/// The generic parameters don't include the erased `Self`, only trait
|
||||
/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
@ -481,8 +481,8 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||
/// reference.
|
||||
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
|
||||
let def_id = tcx.parent(self.def_id);
|
||||
let subst_count = tcx.generics_of(def_id).count() - 1;
|
||||
let args = tcx.mk_args(&self.args[..subst_count]);
|
||||
let args_count = tcx.generics_of(def_id).count() - 1;
|
||||
let args = tcx.mk_args(&self.args[..args_count]);
|
||||
ty::ExistentialTraitRef { def_id, args }
|
||||
}
|
||||
|
||||
@ -534,12 +534,12 @@ impl<'tcx> PolyExistentialProjection<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
/// Performs a substitution suitable for going from a
|
||||
/// Performs a instantiation suitable for going from a
|
||||
/// poly-trait-ref to supertraits that must hold if that
|
||||
/// poly-trait-ref holds. This is slightly different from a normal
|
||||
/// substitution in terms of what happens with bound regions. See
|
||||
/// instantiation in terms of what happens with bound regions. See
|
||||
/// lengthy comment below for details.
|
||||
pub fn subst_supertrait(
|
||||
pub fn instantiate_supertrait(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
@ -556,7 +556,7 @@ impl<'tcx> Clause<'tcx> {
|
||||
// we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we
|
||||
// knew that `Foo<'x>` (for any 'x) then we also know that
|
||||
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
|
||||
// normal substitution.
|
||||
// normal instantiation.
|
||||
//
|
||||
// In terms of why this is sound, the idea is that whenever there
|
||||
// is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
|
||||
@ -582,7 +582,7 @@ impl<'tcx> Clause<'tcx> {
|
||||
// - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x`
|
||||
// has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`,
|
||||
// where both `'x` and `'b` would have a DB index of 1.
|
||||
// The substitution from the input trait-ref is therefore going to be
|
||||
// The instantiation from the input trait-ref is therefore going to be
|
||||
// `'a => 'x` (where `'x` has a DB index of 1).
|
||||
// - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
|
||||
// early-bound parameter and `'b` is a late-bound parameter with a
|
||||
@ -591,17 +591,17 @@ impl<'tcx> Clause<'tcx> {
|
||||
// a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>`
|
||||
// just as we wanted.
|
||||
//
|
||||
// There is only one catch. If we just apply the substitution `'a
|
||||
// => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will
|
||||
// adjust the DB index because we substituting into a binder (it
|
||||
// There is only one catch. If we just apply the instantiation `'a
|
||||
// => 'x` to `for<'b> Bar1<'a,'b>`, the instantiation code will
|
||||
// adjust the DB index because we instantiating into a binder (it
|
||||
// tries to be so smart...) resulting in `for<'x> for<'b>
|
||||
// Bar1<'x,'b>` (we have no syntax for this, so use your
|
||||
// imagination). Basically the 'x will have DB index of 2 and 'b
|
||||
// will have DB index of 1. Not quite what we want. So we apply
|
||||
// the substitution to the *contents* of the trait reference,
|
||||
// the instantiation to the *contents* of the trait reference,
|
||||
// rather than the trait reference itself (put another way, the
|
||||
// substitution code expects equal binding levels in the values
|
||||
// from the substitution and the value being substituted into, and
|
||||
// instantiation code expects equal binding levels in the values
|
||||
// from the instantiation and the value being instantiated into, and
|
||||
// this trick achieves that).
|
||||
|
||||
// Working through the second example:
|
||||
|
@ -208,7 +208,7 @@ impl<'tcx> ClosureArgs<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the substitutions of the closure's parent.
|
||||
/// Returns the generic parameters of the closure's parent.
|
||||
pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
|
||||
self.split().parent_args
|
||||
}
|
||||
@ -615,7 +615,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the substitutions of the coroutine's parent.
|
||||
/// Returns the generic parameters of the coroutine's parent.
|
||||
pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
|
||||
self.split().parent_args
|
||||
}
|
||||
@ -819,7 +819,7 @@ impl<'tcx> UpvarArgs<'tcx> {
|
||||
/// inherited from the item that defined the inline const,
|
||||
/// - R represents the type of the constant.
|
||||
///
|
||||
/// When the inline const is instantiated, `R` is substituted as the actual inferred
|
||||
/// When the inline const is instantiated, `R` is instantiated as the actual inferred
|
||||
/// type of the constant. The reason that `R` is represented as an extra type parameter
|
||||
/// is the same reason that [`ClosureArgs`] have `CS` and `U` as type parameters:
|
||||
/// inline const can reference lifetimes that are internal to the creating function.
|
||||
@ -858,7 +858,7 @@ impl<'tcx> InlineConstArgs<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the substitutions of the inline const's parent.
|
||||
/// Returns the generic parameters of the inline const's parent.
|
||||
pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
|
||||
self.split().parent_args
|
||||
}
|
||||
@ -1105,13 +1105,13 @@ where
|
||||
pub struct AliasTy<'tcx> {
|
||||
/// The parameters of the associated or opaque item.
|
||||
///
|
||||
/// For a projection, these are the substitutions for the trait and the
|
||||
/// GAT substitutions, if there are any.
|
||||
/// For a projection, these are the generic parameters for the trait and the
|
||||
/// GAT parameters, if there are any.
|
||||
///
|
||||
/// For an inherent projection, they consist of the self type and the GAT substitutions,
|
||||
/// For an inherent projection, they consist of the self type and the GAT parameters,
|
||||
/// if there are any.
|
||||
///
|
||||
/// For RPIT the substitutions are for the generics of the function,
|
||||
/// For RPIT the generic parameters are for the generics of the function,
|
||||
/// while for TAIT it is used for the generic parameters of the alias.
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
|
||||
@ -1235,15 +1235,15 @@ impl<'tcx> AliasTy<'tcx> {
|
||||
|
||||
/// The following methods work only with inherent associated type projections.
|
||||
impl<'tcx> AliasTy<'tcx> {
|
||||
/// Transform the substitutions to have the given `impl` args as the base and the GAT args on top of that.
|
||||
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
|
||||
///
|
||||
/// Does the following transformation:
|
||||
///
|
||||
/// ```text
|
||||
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||
///
|
||||
/// I_i impl subst
|
||||
/// P_j GAT subst
|
||||
/// I_i impl args
|
||||
/// P_j GAT args
|
||||
/// ```
|
||||
pub fn rebase_inherent_args_onto_impl(
|
||||
self,
|
||||
@ -1690,7 +1690,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
debug_assert_eq!(
|
||||
closure_args.len(),
|
||||
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
|
||||
"closure constructed with incorrect substitutions"
|
||||
"closure constructed with incorrect generic parameters"
|
||||
);
|
||||
Ty::new(tcx, Closure(def_id, closure_args))
|
||||
}
|
||||
@ -1704,7 +1704,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
debug_assert_eq!(
|
||||
closure_args.len(),
|
||||
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
|
||||
"closure constructed with incorrect substitutions"
|
||||
"closure constructed with incorrect generic parameters"
|
||||
);
|
||||
Ty::new(tcx, CoroutineClosure(def_id, closure_args))
|
||||
}
|
||||
@ -1718,7 +1718,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
debug_assert_eq!(
|
||||
coroutine_args.len(),
|
||||
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
|
||||
"coroutine constructed with incorrect number of substitutions"
|
||||
"coroutine constructed with incorrect number of generic parameters"
|
||||
);
|
||||
Ty::new(tcx, Coroutine(def_id, coroutine_args))
|
||||
}
|
||||
@ -2530,7 +2530,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
}
|
||||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or substituted. This includes all primitive types, but also
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, sice even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
|
@ -55,19 +55,19 @@ pub struct TypeckResults<'tcx> {
|
||||
/// typeck::check::fn_ctxt for details.
|
||||
node_types: ItemLocalMap<Ty<'tcx>>,
|
||||
|
||||
/// Stores the type parameters which were substituted to obtain the type
|
||||
/// Stores the type parameters which were instantiated to obtain the type
|
||||
/// of this node. This only applies to nodes that refer to entities
|
||||
/// parameterized by type parameters, such as generic fns, types, or
|
||||
/// other items.
|
||||
node_args: ItemLocalMap<GenericArgsRef<'tcx>>,
|
||||
|
||||
/// This will either store the canonicalized types provided by the user
|
||||
/// or the substitutions that the user explicitly gave (if any) attached
|
||||
/// or the generic parameters that the user explicitly gave (if any) attached
|
||||
/// to `id`. These will not include any inferred values. The canonical form
|
||||
/// is used to capture things like `_` or other unspecified values.
|
||||
///
|
||||
/// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
|
||||
/// canonical substitutions would include only `for<X> { Vec<X> }`.
|
||||
/// canonical generic parameters would include only `for<X> { Vec<X> }`.
|
||||
///
|
||||
/// See also `AscribeUserType` statement in MIR.
|
||||
user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
|
||||
@ -348,7 +348,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
}
|
||||
|
||||
/// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
|
||||
/// doesn't provide type parameter substitutions.
|
||||
/// doesn't provide type parameter args.
|
||||
///
|
||||
/// [`expr_ty`]: TypeckResults::expr_ty
|
||||
pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
|
||||
@ -360,9 +360,9 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
/// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
|
||||
/// some cases, we insert `Adjustment` annotations such as auto-deref or
|
||||
/// auto-ref. The type returned by this function does not consider such
|
||||
/// adjustments. See `expr_ty_adjusted()` instead.
|
||||
/// adjustments. See [`Self::expr_ty_adjusted`] instead.
|
||||
///
|
||||
/// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
|
||||
/// NB (2): This type doesn't provide type parameter args; e.g., if you
|
||||
/// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
|
||||
/// instead of `fn(ty) -> T with T = isize`.
|
||||
pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
|
||||
@ -627,7 +627,7 @@ pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
/// given substitutions applied.
|
||||
/// given generic parameters applied.
|
||||
TypeOf(DefId, UserArgs<'tcx>),
|
||||
}
|
||||
|
||||
@ -636,7 +636,7 @@ pub trait IsIdentity {
|
||||
}
|
||||
|
||||
impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
|
||||
/// Returns `true` if this represents the generic parameters of the form `[?0, ?1, ?2]`,
|
||||
/// i.e., each thing is mapped to a canonical variable with the same index.
|
||||
fn is_identity(&self) -> bool {
|
||||
match self.value {
|
||||
@ -650,7 +650,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
match kind.unpack() {
|
||||
GenericArgKind::Type(ty) => match ty.kind() {
|
||||
ty::Bound(debruijn, b) => {
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(*debruijn, ty::INNERMOST);
|
||||
cvar == b.var
|
||||
}
|
||||
@ -659,7 +659,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
|
||||
GenericArgKind::Lifetime(r) => match *r {
|
||||
ty::ReBound(debruijn, br) => {
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
cvar == br.var
|
||||
}
|
||||
@ -668,7 +668,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
|
||||
GenericArgKind::Const(ct) => match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, b) => {
|
||||
// We only allow a `ty::INNERMOST` index in substitutions.
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
cvar == b
|
||||
}
|
||||
|
@ -541,13 +541,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note
|
||||
/// that closures have a `DefId`, but the closure *expression* also
|
||||
/// has a `HirId` that is located within the context where the
|
||||
/// closure appears (and, sadly, a corresponding `NodeId`, since
|
||||
/// those are not yet phased out). The parent of the closure's
|
||||
/// `DefId` will also be the context where it appears.
|
||||
pub fn is_closure_or_coroutine(self, def_id: DefId) -> bool {
|
||||
/// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure
|
||||
/// (i.e. an async closure). These are all represented by `hir::Closure`, and all
|
||||
/// have the same `DefKind`.
|
||||
///
|
||||
/// Note that closures have a `DefId`, but the closure *expression* also has a
|
||||
// `HirId` that is located within the context where the closure appears (and, sadly,
|
||||
// a corresponding `NodeId`, since those are not yet phased out). The parent of
|
||||
// the closure's `DefId` will also be the context where it appears.
|
||||
pub fn is_closure_like(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Closure)
|
||||
}
|
||||
|
||||
|
@ -811,7 +811,7 @@ impl<'tcx> Cx<'tcx> {
|
||||
let user_provided_type = match res {
|
||||
// A reference to something callable -- e.g., a fn, method, or
|
||||
// a tuple-struct or tuple-variant. This has the type of a
|
||||
// `Fn` but with the user-given substitutions.
|
||||
// `Fn` but with the user-given generic parameters.
|
||||
Res::Def(DefKind::Fn, _)
|
||||
| Res::Def(DefKind::AssocFn, _)
|
||||
| Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
|
||||
@ -822,7 +822,7 @@ impl<'tcx> Cx<'tcx> {
|
||||
|
||||
// A unit struct/variant which is used as a value (e.g.,
|
||||
// `None`). This has the type of the enum/struct that defines
|
||||
// this variant -- but with the substitutions given by the
|
||||
// this variant -- but with the generic parameters given by the
|
||||
// user.
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
|
||||
self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new)
|
||||
|
@ -7,7 +7,7 @@ pub(crate) trait UserAnnotatedTyHelpers<'tcx> {
|
||||
fn typeck_results(&self) -> &ty::TypeckResults<'tcx>;
|
||||
|
||||
/// Looks up the type associated with this hir-id and applies the
|
||||
/// user-given substitutions; the hir-id must map to a suitable
|
||||
/// user-given generic parameters; the hir-id must map to a suitable
|
||||
/// type.
|
||||
fn user_args_applied_to_ty_of_hir_id(
|
||||
&self,
|
||||
|
@ -36,10 +36,10 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b
|
||||
ty::Tuple(tys) => {
|
||||
depth == 0 || tys.iter().any(|ty| may_contain_reference(ty, depth - 1, tcx))
|
||||
}
|
||||
ty::Adt(adt, subst) => {
|
||||
ty::Adt(adt, args) => {
|
||||
depth == 0
|
||||
|| adt.variants().iter().any(|v| {
|
||||
v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, subst), depth - 1, tcx))
|
||||
v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, args), depth - 1, tcx))
|
||||
})
|
||||
}
|
||||
// Conservative fallback
|
||||
|
@ -138,7 +138,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
|
||||
let (span, visible_macro) =
|
||||
unexpand_into_body_span_with_visible_macro(expn_span, body_span)?;
|
||||
|
||||
Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_or_coroutine(statement)))
|
||||
Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement)))
|
||||
});
|
||||
|
||||
let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| {
|
||||
@ -153,7 +153,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
|
||||
})
|
||||
}
|
||||
|
||||
fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool {
|
||||
fn is_closure_like(statement: &Statement<'_>) -> bool {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind {
|
||||
AggregateKind::Closure(_, _)
|
||||
|
@ -205,8 +205,8 @@ pub fn deduced_param_attrs<'tcx>(
|
||||
|(arg_index, local_decl)| DeducedParamAttrs {
|
||||
read_only: !deduce_read_only.mutable_args.contains(arg_index)
|
||||
// We must normalize here to reveal opaques and normalize
|
||||
// their substs, otherwise we'll see exponential blow-up in
|
||||
// compile times: #113372
|
||||
// their generic parameters, otherwise we'll see exponential
|
||||
// blow-up in compile times: #113372
|
||||
&& tcx
|
||||
.normalize_erasing_regions(param_env, local_decl.ty)
|
||||
.is_freeze(tcx, param_env),
|
||||
|
@ -63,7 +63,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
|
||||
|
||||
impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
|
||||
/// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the
|
||||
/// function defined by `def_id` with the substitutions `args_ref`.
|
||||
/// function defined by `def_id` with the generic parameters `args_ref`.
|
||||
fn check_bound_args(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
@ -83,11 +83,11 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
|
||||
for inner_ty in arg_def.walk().filter_map(|arg| arg.as_type()) {
|
||||
// If the inner type matches the type bound by `Pointer`
|
||||
if inner_ty == bound_ty {
|
||||
// Do a substitution using the parameters from the callsite
|
||||
let subst_ty =
|
||||
// Do an instantiation using the parameters from the callsite
|
||||
let instantiated_ty =
|
||||
EarlyBinder::bind(inner_ty).instantiate(self.tcx, args_ref);
|
||||
if let Some((fn_id, fn_args)) =
|
||||
FunctionItemRefChecker::is_fn_ref(subst_ty)
|
||||
FunctionItemRefChecker::is_fn_ref(instantiated_ty)
|
||||
{
|
||||
let mut span = self.nth_arg_span(args, arg_num);
|
||||
if span.from_expansion() {
|
||||
|
@ -853,10 +853,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||
|
||||
fn simplify_discriminant(&mut self, place: VnIndex) -> Option<VnIndex> {
|
||||
if let Value::Aggregate(enum_ty, variant, _) = *self.get(place)
|
||||
&& let AggregateTy::Def(enum_did, enum_substs) = enum_ty
|
||||
&& let AggregateTy::Def(enum_did, enum_args) = enum_ty
|
||||
&& let DefKind::Enum = self.tcx.def_kind(enum_did)
|
||||
{
|
||||
let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_substs);
|
||||
let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args);
|
||||
let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?;
|
||||
return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
|
||||
}
|
||||
@ -899,13 +899,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||
assert!(!fields.is_empty());
|
||||
(AggregateTy::Tuple, FIRST_VARIANT)
|
||||
}
|
||||
AggregateKind::Closure(did, substs)
|
||||
| AggregateKind::CoroutineClosure(did, substs)
|
||||
| AggregateKind::Coroutine(did, substs) => {
|
||||
(AggregateTy::Def(did, substs), FIRST_VARIANT)
|
||||
}
|
||||
AggregateKind::Adt(did, variant_index, substs, _, None) => {
|
||||
(AggregateTy::Def(did, substs), variant_index)
|
||||
AggregateKind::Closure(did, args)
|
||||
| AggregateKind::CoroutineClosure(did, args)
|
||||
| AggregateKind::Coroutine(did, args) => (AggregateTy::Def(did, args), FIRST_VARIANT),
|
||||
AggregateKind::Adt(did, variant_index, args, _, None) => {
|
||||
(AggregateTy::Def(did, args), variant_index)
|
||||
}
|
||||
// Do not track unions.
|
||||
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
|
||||
|
@ -80,7 +80,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
|
||||
}
|
||||
// These have no own callable MIR.
|
||||
InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue,
|
||||
// These have MIR and if that MIR is inlined, substituted and then inlining is run
|
||||
// These have MIR and if that MIR is inlined, instantiated and then inlining is run
|
||||
// again, a function item can end up getting inlined. Thus we'll be able to cause
|
||||
// a cycle that way
|
||||
InstanceDef::VTableShim(_)
|
||||
@ -95,7 +95,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
|
||||
// This shim does not call any other functions, thus there can be no recursion.
|
||||
InstanceDef::FnPtrAddrShim(..) => continue,
|
||||
InstanceDef::DropGlue(..) => {
|
||||
// FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
|
||||
// FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to
|
||||
// have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
|
||||
// needs some more analysis.
|
||||
if callee.has_param() {
|
||||
|
@ -208,7 +208,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
// Only bother looking more if it's easy to know what we're calling
|
||||
let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return };
|
||||
|
||||
// Clone needs one subst, so we can cheaply rule out other stuff
|
||||
// Clone needs one arg, so we can cheaply rule out other stuff
|
||||
if fn_args.len() != 1 {
|
||||
return;
|
||||
}
|
||||
|
@ -436,7 +436,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
|
||||
//
|
||||
// We manually filter the predicates, skipping anything that's not
|
||||
// "global". We are in a potentially generic context
|
||||
// (e.g. we are evaluating a function without substituting generic
|
||||
// (e.g. we are evaluating a function without instantiating generic
|
||||
// parameters, so this filtering serves two purposes:
|
||||
//
|
||||
// 1. We skip evaluating any predicates that we would
|
||||
@ -576,10 +576,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
&inline::Inline,
|
||||
// Code from other crates may have storage markers, so this needs to happen after inlining.
|
||||
&remove_storage_markers::RemoveStorageMarkers,
|
||||
// Inlining and substitution may introduce ZST and useless drops.
|
||||
// Inlining and instantiation may introduce ZST and useless drops.
|
||||
&remove_zsts::RemoveZsts,
|
||||
&remove_unneeded_drops::RemoveUnneededDrops,
|
||||
// Type substitution may create uninhabited enums.
|
||||
// Type instantiation may create uninhabited enums.
|
||||
&uninhabited_enum_branching::UninhabitedEnumBranching,
|
||||
&unreachable_prop::UnreachablePropagation,
|
||||
&o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching),
|
||||
@ -673,7 +673,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
|
||||
}
|
||||
|
||||
/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
|
||||
/// constant evaluation once all substitutions become known.
|
||||
/// constant evaluation once all generic parameters become known.
|
||||
fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_>> {
|
||||
if tcx.is_constructor(def.to_def_id()) {
|
||||
return tcx.arena.alloc(IndexVec::new());
|
||||
|
@ -44,7 +44,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
|
||||
///
|
||||
/// # Liveness
|
||||
///
|
||||
/// When performing a substitution, we must take care not to introduce uses of dangling locals.
|
||||
/// When performing an instantiation, we must take care not to introduce uses of dangling locals.
|
||||
/// To ensure this, we walk the body with the `MaybeStorageDead` dataflow analysis:
|
||||
/// - if we want to replace `*x` by reborrow `*y` and `y` may be dead, we allow replacement and
|
||||
/// mark storage statements on `y` for removal;
|
||||
@ -55,7 +55,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
|
||||
///
|
||||
/// For `&mut` borrows, we also need to preserve the uniqueness property:
|
||||
/// we must avoid creating a state where we interleave uses of `*_1` and `_2`.
|
||||
/// To do it, we only perform full substitution of mutable borrows:
|
||||
/// To do it, we only perform full instantiation of mutable borrows:
|
||||
/// we replace either all or none of the occurrences of `*_1`.
|
||||
///
|
||||
/// Some care has to be taken when `_1` is copied in other locals.
|
||||
@ -63,10 +63,10 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
|
||||
/// _3 = *_1;
|
||||
/// _4 = _1
|
||||
/// _5 = *_4
|
||||
/// In such cases, fully substituting `_1` means fully substituting all of the copies.
|
||||
/// In such cases, fully instantiating `_1` means fully instantiating all of the copies.
|
||||
///
|
||||
/// For immutable borrows, we do not need to preserve such uniqueness property,
|
||||
/// so we perform all the possible substitutions without removing the `_1 = &_2` statement.
|
||||
/// so we perform all the possible instantiations without removing the `_1 = &_2` statement.
|
||||
pub struct ReferencePropagation;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReferencePropagation {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user