Skip to content

Commit ebe21ac

Browse files
committed
Infer all inference variables 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.
1 parent 24a8d3b commit ebe21ac

File tree

5 files changed

+36
-144
lines changed

5 files changed

+36
-144
lines changed

compiler/rustc_middle/src/ty/mod.rs

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

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

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 {

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
}

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

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)