Skip to content

Commit 7d36d69

Browse files
Rollup merge of #87200 - oli-obk:fixup_fixup_opaque_types, r=nikomatsakis
TAIT: Infer all inference variables in opaque type substitutions via InferCx The previous algorithm was correct for the example given in its documentation, but when the TAIT was declared as a free item instead of an associated item, the generic parameters were the wrong ones. cc `@spastorino` r? `@nikomatsakis`
2 parents e596aa2 + ebe21ac commit 7d36d69

File tree

6 files changed

+42
-152
lines changed

6 files changed

+42
-152
lines changed

Diff for: compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
857857
}
858858
}
859859

860-
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
860+
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
861861
pub struct OpaqueTypeKey<'tcx> {
862862
pub def_id: DefId,
863863
pub substs: SubstsRef<'tcx>,

Diff for: compiler/rustc_trait_selection/src/opaque_types.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
568568
/// - `substs`, the substs used to instantiate this opaque type
569569
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
570570
/// `opaque_defn.concrete_ty`
571+
#[instrument(skip(self))]
571572
fn infer_opaque_definition_from_instantiation(
572573
&self,
573574
opaque_type_key: OpaqueTypeKey<'tcx>,
@@ -576,18 +577,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
576577
) -> Ty<'tcx> {
577578
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
578579

579-
debug!(
580-
"infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
581-
def_id, instantiated_ty
582-
);
583-
584580
// Use substs to build up a reverse map from regions to their
585581
// identity mappings. This is necessary because of `impl
586582
// Trait` lifetimes are computed by replacing existing
587583
// lifetimes with 'static and remapping only those used in the
588584
// `impl Trait` return type, resulting in the parameters
589585
// shifting.
590586
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
587+
debug!(?id_substs);
591588
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
592589
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
593590

@@ -602,7 +599,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
602599
instantiated_ty,
603600
span,
604601
));
605-
debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty);
602+
debug!(?definition_ty);
606603

607604
definition_ty
608605
}
@@ -857,14 +854,15 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
857854
self.tcx.mk_generator(def_id, substs, movability)
858855
}
859856

860-
ty::Param(..) => {
857+
ty::Param(param) => {
861858
// Look it up in the substitution list.
862859
match self.map.get(&ty.into()).map(|k| k.unpack()) {
863860
// Found it in the substitution list; replace with the parameter from the
864861
// opaque type.
865862
Some(GenericArgKind::Type(t1)) => t1,
866863
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
867864
None => {
865+
debug!(?param, ?self.map);
868866
self.tcx
869867
.sess
870868
.struct_span_err(
@@ -931,8 +929,8 @@ struct Instantiator<'a, 'tcx> {
931929
}
932930

933931
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
932+
#[instrument(skip(self))]
934933
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
935-
debug!("instantiate_opaque_types_in_map(value={:?})", value);
936934
let tcx = self.infcx.tcx;
937935
value.fold_with(&mut BottomUpFolder {
938936
tcx,

Diff for: compiler/rustc_typeck/src/check/mod.rs

+1-116
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,9 @@ use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
112112
use rustc_index::bit_set::BitSet;
113113
use rustc_index::vec::Idx;
114114
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
115-
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
116115
use rustc_middle::ty::query::Providers;
117-
use rustc_middle::ty::subst::GenericArgKind;
118116
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
119-
use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
117+
use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
120118
use rustc_session::config;
121119
use rustc_session::parse::feature_err;
122120
use rustc_session::Session;
@@ -321,117 +319,6 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDe
321319
&*tcx.typeck(def_id).used_trait_imports
322320
}
323321

324-
/// Inspects the substs of opaque types, replacing any inference variables
325-
/// with proper generic parameter from the identity substs.
326-
///
327-
/// This is run after we normalize the function signature, to fix any inference
328-
/// variables introduced by the projection of associated types. This ensures that
329-
/// any opaque types used in the signature continue to refer to generic parameters,
330-
/// allowing them to be considered for defining uses in the function body
331-
///
332-
/// For example, consider this code.
333-
///
334-
/// ```rust
335-
/// trait MyTrait {
336-
/// type MyItem;
337-
/// fn use_it(self) -> Self::MyItem
338-
/// }
339-
/// impl<T, I> MyTrait for T where T: Iterator<Item = I> {
340-
/// type MyItem = impl Iterator<Item = I>;
341-
/// fn use_it(self) -> Self::MyItem {
342-
/// self
343-
/// }
344-
/// }
345-
/// ```
346-
///
347-
/// When we normalize the signature of `use_it` from the impl block,
348-
/// we will normalize `Self::MyItem` to the opaque type `impl Iterator<Item = I>`
349-
/// However, this projection result may contain inference variables, due
350-
/// to the way that projection works. We didn't have any inference variables
351-
/// in the signature to begin with - leaving them in will cause us to incorrectly
352-
/// conclude that we don't have a defining use of `MyItem`. By mapping inference
353-
/// variables back to the actual generic parameters, we will correctly see that
354-
/// we have a defining use of `MyItem`
355-
fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: T) -> T
356-
where
357-
T: TypeFoldable<'tcx>,
358-
{
359-
struct FixupFolder<'tcx> {
360-
tcx: TyCtxt<'tcx>,
361-
}
362-
363-
impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> {
364-
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
365-
self.tcx
366-
}
367-
368-
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
369-
match *ty.kind() {
370-
ty::Opaque(def_id, substs) => {
371-
debug!("fixup_opaque_types: found type {:?}", ty);
372-
// Here, we replace any inference variables that occur within
373-
// the substs of an opaque type. By definition, any type occurring
374-
// in the substs has a corresponding generic parameter, which is what
375-
// we replace it with.
376-
// This replacement is only run on the function signature, so any
377-
// inference variables that we come across must be the rust of projection
378-
// (there's no other way for a user to get inference variables into
379-
// a function signature).
380-
if ty.needs_infer() {
381-
let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| {
382-
let old_param = substs[param.index as usize];
383-
match old_param.unpack() {
384-
GenericArgKind::Type(old_ty) => {
385-
if let ty::Infer(_) = old_ty.kind() {
386-
// Replace inference type with a generic parameter
387-
self.tcx.mk_param_from_def(param)
388-
} else {
389-
old_param.fold_with(self)
390-
}
391-
}
392-
GenericArgKind::Const(old_const) => {
393-
if let ty::ConstKind::Infer(_) = old_const.val {
394-
// This should never happen - we currently do not support
395-
// 'const projections', e.g.:
396-
// `impl<T: SomeTrait> MyTrait for T where <T as SomeTrait>::MyConst == 25`
397-
// which should be the only way for us to end up with a const inference
398-
// variable after projection. If Rust ever gains support for this kind
399-
// of projection, this should *probably* be changed to
400-
// `self.tcx.mk_param_from_def(param)`
401-
bug!(
402-
"Found infer const: `{:?}` in opaque type: {:?}",
403-
old_const,
404-
ty
405-
);
406-
} else {
407-
old_param.fold_with(self)
408-
}
409-
}
410-
GenericArgKind::Lifetime(old_region) => {
411-
if let RegionKind::ReVar(_) = old_region {
412-
self.tcx.mk_param_from_def(param)
413-
} else {
414-
old_param.fold_with(self)
415-
}
416-
}
417-
}
418-
});
419-
let new_ty = self.tcx.mk_opaque(def_id, new_substs);
420-
debug!("fixup_opaque_types: new type: {:?}", new_ty);
421-
new_ty
422-
} else {
423-
ty
424-
}
425-
}
426-
_ => ty.super_fold_with(self),
427-
}
428-
}
429-
}
430-
431-
debug!("fixup_opaque_types({:?})", val);
432-
val.fold_with(&mut FixupFolder { tcx })
433-
}
434-
435322
fn typeck_const_arg<'tcx>(
436323
tcx: TyCtxt<'tcx>,
437324
(did, param_did): (LocalDefId, DefId),
@@ -510,8 +397,6 @@ fn typeck_with_fallback<'tcx>(
510397
fn_sig,
511398
);
512399

513-
let fn_sig = fixup_opaque_types(tcx, fn_sig);
514-
515400
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
516401
fcx
517402
} else {

Diff for: compiler/rustc_typeck/src/check/writeback.rs

+28-24
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
496496

497497
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
498498

499+
let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
500+
499501
// Prevent:
500502
// * `fn foo<T>() -> Foo<T>`
501503
// * `fn foo<T: Bound + Other>() -> Foo<T>`
@@ -508,6 +510,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
508510
// fn foo<U>() -> Foo<U> { .. }
509511
// ```
510512
// figures out the concrete type with `U`, but the stored type is with `T`.
513+
514+
// FIXME: why are we calling this here? This seems too early, and duplicated.
511515
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
512516
opaque_type_key,
513517
instantiated_ty,
@@ -529,33 +533,33 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
529533
}
530534
}
531535

532-
if !opaque_type_key.substs.needs_infer() {
533-
// We only want to add an entry into `concrete_opaque_types`
534-
// if we actually found a defining usage of this opaque type.
535-
// Otherwise, we do nothing - we'll either find a defining usage
536-
// in some other location, or we'll end up emitting an error due
537-
// to the lack of defining usage
538-
if !skip_add {
539-
let old_concrete_ty = self
540-
.typeck_results
541-
.concrete_opaque_types
542-
.insert(opaque_type_key, definition_ty);
543-
if let Some(old_concrete_ty) = old_concrete_ty {
544-
if old_concrete_ty != definition_ty {
545-
span_bug!(
546-
span,
547-
"`visit_opaque_types` tried to write different types for the same \
536+
if opaque_type_key.substs.needs_infer() {
537+
span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
538+
}
539+
540+
// We only want to add an entry into `concrete_opaque_types`
541+
// if we actually found a defining usage of this opaque type.
542+
// Otherwise, we do nothing - we'll either find a defining usage
543+
// in some other location, or we'll end up emitting an error due
544+
// to the lack of defining usage
545+
if !skip_add {
546+
let old_concrete_ty = self
547+
.typeck_results
548+
.concrete_opaque_types
549+
.insert(opaque_type_key, definition_ty);
550+
if let Some(old_concrete_ty) = old_concrete_ty {
551+
if old_concrete_ty != definition_ty {
552+
span_bug!(
553+
span,
554+
"`visit_opaque_types` tried to write different types for the same \
548555
opaque type: {:?}, {:?}, {:?}, {:?}",
549-
opaque_type_key.def_id,
550-
definition_ty,
551-
opaque_defn,
552-
old_concrete_ty,
553-
);
554-
}
556+
opaque_type_key.def_id,
557+
definition_ty,
558+
opaque_defn,
559+
old_concrete_ty,
560+
);
555561
}
556562
}
557-
} else {
558-
self.tcx().sess.delay_span_bug(span, "`opaque_defn` has inference variables");
559563
}
560564
}
561565
}

Diff for: src/test/ui/type-alias-impl-trait/issue-60371.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ trait Bug {
99
impl Bug for &() {
1010
type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable
1111
//~^ ERROR the trait bound `(): Bug` is not satisfied
12-
//~^^ ERROR could not find defining uses
12+
//~^^ ERROR the trait bound `(): Bug` is not satisfied
1313

1414
const FUN: fn() -> Self::Item = || ();
1515
//~^ ERROR type alias impl trait is not permitted here

Diff for: src/test/ui/type-alias-impl-trait/issue-60371.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ LL | type Item = impl Bug;
2525
= help: the following implementations were found:
2626
<&() as Bug>
2727

28-
error: could not find defining uses
28+
error[E0277]: the trait bound `(): Bug` is not satisfied
2929
--> $DIR/issue-60371.rs:10:17
3030
|
3131
LL | type Item = impl Bug;
32-
| ^^^^^^^^
32+
| ^^^^^^^^ the trait `Bug` is not implemented for `()`
33+
|
34+
= help: the following implementations were found:
35+
<&() as Bug>
3336

3437
error: aborting due to 4 previous errors
3538

0 commit comments

Comments
 (0)