Skip to content

Commit 549f545

Browse files
committed
Require all type variables to satisfy the impl trait bounds
1 parent 1625296 commit 549f545

File tree

6 files changed

+100
-35
lines changed

6 files changed

+100
-35
lines changed

compiler/rustc_mir/src/borrow_check/type_check/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13071307
};
13081308
debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
13091309
let subst_opaque_defn_ty =
1310-
opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
1310+
opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs[0]);
13111311
let renumbered_opaque_defn_ty =
13121312
renumber::renumber_regions(infcx, subst_opaque_defn_ty);
13131313

@@ -1328,7 +1328,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13281328
opaque_def_id,
13291329
ty::ResolvedOpaqueTy {
13301330
concrete_type: renumbered_opaque_defn_ty,
1331-
substs: opaque_decl.substs,
1331+
substs: opaque_decl.substs[0],
13321332
},
13331333
));
13341334
} else {

compiler/rustc_trait_selection/src/opaque_types.rs

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisit
1313
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
1414
use rustc_middle::ty::{self, Ty, TyCtxt};
1515
use rustc_span::Span;
16+
use smallvec::{smallvec, SmallVec};
1617

1718
use std::ops::ControlFlow;
1819

@@ -37,7 +38,11 @@ pub struct OpaqueTypeDecl<'tcx> {
3738
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
3839
///
3940
/// then `substs` would be `['a, T]`.
40-
pub substs: SubstsRef<'tcx>,
41+
///
42+
/// In case there are multiple conflicting substs an error has already
43+
/// been reported, but we still store the additional substs here in order
44+
/// to allow for better diagnostics later.
45+
pub substs: SmallVec<[SubstsRef<'tcx>; 1]>,
4146

4247
/// The span of this particular definition of the opaque type. So
4348
/// for example:
@@ -429,11 +434,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
429434
// If there are required region bounds, we can use them.
430435
if opaque_defn.has_required_region_bounds {
431436
let bounds = tcx.explicit_item_bounds(def_id);
432-
debug!("constrain_opaque_type: predicates: {:#?}", bounds);
437+
debug!(?bounds, "predicates");
433438
let bounds: Vec<_> =
434-
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
435-
debug!("constrain_opaque_type: bounds={:#?}", bounds);
436-
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
439+
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs[0])).collect();
440+
debug!(?bounds);
441+
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs[0]);
437442

438443
let required_region_bounds =
439444
required_region_bounds(tcx, opaque_type, bounds.into_iter());
@@ -459,7 +464,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
459464
// second.
460465
let mut least_region = None;
461466

462-
for subst_arg in &opaque_defn.substs[first_own_region..] {
467+
for subst_arg in &opaque_defn.substs[0][first_own_region..] {
463468
let subst_region = match subst_arg.unpack() {
464469
GenericArgKind::Lifetime(r) => r,
465470
GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
@@ -532,7 +537,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
532537
// type can be equal to any of the region parameters of the
533538
// opaque type definition.
534539
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
535-
opaque_defn.substs[first_own_region..]
540+
opaque_defn.substs[0][first_own_region..]
536541
.iter()
537542
.filter_map(|arg| match arg.unpack() {
538543
GenericArgKind::Lifetime(r) => Some(r),
@@ -1095,18 +1100,40 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
10951100
let tcx = infcx.tcx;
10961101

10971102
// Use the same type variable if the exact same opaque type appears more
1098-
// than once in the return type (e.g., if it's passed to a type alias).
1099-
if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
1100-
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
1101-
return opaque_defn.concrete_ty;
1103+
// than once in a function (e.g., if it's passed to a type alias).
1104+
if let Some(opaque_defn) = self.opaque_types.get_mut(&def_id) {
1105+
debug!(?opaque_defn, "found already known concrete type");
1106+
if opaque_defn.substs.contains(&substs) {
1107+
// Already seen this concrete type
1108+
return opaque_defn.concrete_ty;
1109+
} else {
1110+
// Don't emit multiple errors for the same set of substs
1111+
opaque_defn.substs.push(substs);
1112+
tcx.sess
1113+
.struct_span_err(
1114+
self.value_span,
1115+
&format!(
1116+
"defining use generics {:?} differ from previous defining use",
1117+
substs
1118+
),
1119+
)
1120+
.span_note(
1121+
opaque_defn.definition_span,
1122+
&format!(
1123+
"previous defining use with different generics {:?} found here",
1124+
opaque_defn.substs[0]
1125+
),
1126+
)
1127+
.delay_as_bug();
1128+
}
11021129
}
11031130
let span = tcx.def_span(def_id);
11041131
debug!(?self.value_span, ?span);
11051132
let ty_var = infcx
11061133
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
11071134

11081135
let item_bounds = tcx.explicit_item_bounds(def_id);
1109-
debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
1136+
debug!(?item_bounds);
11101137
let bounds: Vec<_> =
11111138
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
11121139

@@ -1115,16 +1142,16 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
11151142
infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, bounds);
11161143
self.obligations.extend(obligations);
11171144

1118-
debug!("instantiate_opaque_types: bounds={:?}", bounds);
1145+
debug!(?bounds);
11191146

11201147
let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
1121-
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
1148+
debug!(?required_region_bounds);
11221149

11231150
// Make sure that we are in fact defining the *entire* type
11241151
// (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
11251152
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
1126-
debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,);
1127-
debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),);
1153+
debug!(?self.param_env,);
1154+
debug!(generics= ?tcx.generics_of(def_id),);
11281155

11291156
// Ideally, we'd get the span where *this specific `ty` came
11301157
// from*, but right now we just use the span from the overall
@@ -1133,18 +1160,22 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
11331160
// Foo, impl Bar)`.
11341161
let definition_span = self.value_span;
11351162

1136-
self.opaque_types.insert(
1137-
def_id,
1138-
OpaqueTypeDecl {
1139-
opaque_type: ty,
1140-
substs,
1141-
definition_span,
1142-
concrete_ty: ty_var,
1143-
has_required_region_bounds: !required_region_bounds.is_empty(),
1144-
origin,
1145-
},
1146-
);
1147-
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
1163+
// We only keep the first concrete type var, as we will already error
1164+
// out if there are multiple due to the conflicting obligations
1165+
if !self.opaque_types.contains_key(&def_id) {
1166+
self.opaque_types.insert(
1167+
def_id,
1168+
OpaqueTypeDecl {
1169+
opaque_type: ty,
1170+
substs: smallvec![substs],
1171+
definition_span,
1172+
concrete_ty: ty_var,
1173+
has_required_region_bounds: !required_region_bounds.is_empty(),
1174+
origin,
1175+
},
1176+
);
1177+
}
1178+
debug!(?ty_var);
11481179

11491180
for predicate in &bounds {
11501181
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {

compiler/rustc_typeck/src/check/check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ fn check_opaque_meets_bounds<'tcx>(
741741
for (def_id, opaque_defn) in opaque_type_map {
742742
match infcx
743743
.at(&misc_cause, param_env)
744-
.eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
744+
.eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs[0]))
745745
{
746746
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
747747
Err(ty_err) => tcx.sess.delay_span_bug(

compiler/rustc_typeck/src/check/writeback.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
515515
// figures out the concrete type with `U`, but the stored type is with `T`.
516516
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
517517
def_id,
518-
opaque_defn.substs,
518+
opaque_defn.substs[0],
519519
instantiated_ty,
520520
span,
521521
);
@@ -535,7 +535,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
535535
}
536536
}
537537

538-
if !opaque_defn.substs.needs_infer() {
538+
if !opaque_defn.substs[0].needs_infer() {
539539
// We only want to add an entry into `concrete_opaque_types`
540540
// if we actually found a defining usage of this opaque type.
541541
// Otherwise, we do nothing - we'll either find a defining usage
@@ -544,12 +544,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
544544
if !skip_add {
545545
let new = ty::ResolvedOpaqueTy {
546546
concrete_type: definition_ty,
547-
substs: opaque_defn.substs,
547+
substs: opaque_defn.substs[0],
548548
};
549549

550+
debug!(?def_id, ?new, "inserting opaque type resolution");
550551
let old = self.typeck_results.concrete_opaque_types.insert(def_id, new);
551552
if let Some(old) = old {
552-
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
553+
debug!(?old, "duplicate insertion");
554+
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs[0]
555+
{
553556
span_bug!(
554557
span,
555558
"`visit_opaque_types` tried to write different types for the same \
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// https://github.com/rust-lang/rust/issues/73481
2+
// This test used to cause unsoundness, since one of the two possible
3+
// resolutions was chosen at random instead of erroring due to conflicts.
4+
5+
#![feature(min_type_alias_impl_trait)]
6+
7+
type X<A, B> = impl Into<&'static A>;
8+
//~^ the trait bound `&'static B: From<&A>` is not satisfied
9+
10+
fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
11+
(a, a)
12+
}
13+
14+
fn main() {
15+
println!("{}", <X<_, _> as Into<&String>>::into(f(&[1isize, 2, 3], String::new()).1));
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
2+
--> $DIR/multiple-def-uses-in-one-fn.rs:7:16
3+
|
4+
LL | type X<A, B> = impl Into<&'static A>;
5+
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
6+
|
7+
= note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
8+
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
9+
|
10+
LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)