Skip to content

Commit 6f83dcc

Browse files
committed
Restrict concrete types to equivalent types
1 parent cf01b51 commit 6f83dcc

25 files changed

+264
-33
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> {
233233
abi
234234
});
235235

236+
impl_stable_hash_for!(struct ty::ResolvedOpaqueTy<'tcx> {
237+
concrete_type,
238+
substs
239+
});
240+
236241
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
237242
where T: HashStable<StableHashingContext<'a>>
238243
{

src/librustc/infer/opaque_types/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub struct OpaqueTypeDecl<'tcx> {
2626
///
2727
/// winds up desugared to:
2828
///
29-
/// abstract type Foo<'x, T>: Trait<'x>
29+
/// abstract type Foo<'x, X>: Trait<'x>
3030
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
3131
///
3232
/// then `substs` would be `['a, T]`.

src/librustc/ty/context.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,17 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
315315
}
316316
}
317317

318+
/// All information necessary to validate and reveal an `impl Trait` or `existential Type`
319+
#[derive(RustcEncodable, RustcDecodable, Debug)]
320+
pub struct ResolvedOpaqueTy<'tcx> {
321+
/// The revealed type as seen by this function.
322+
pub concrete_type: Ty<'tcx>,
323+
/// Generic parameters on the opaque type as passed by this function.
324+
/// For `existential type Foo<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }` this is `[T, U]`, not
325+
/// `[A, B]`
326+
pub substs: &'tcx Substs<'tcx>,
327+
}
328+
318329
#[derive(RustcEncodable, RustcDecodable, Debug)]
319330
pub struct TypeckTables<'tcx> {
320331
/// The HirId::owner all ItemLocalIds in this table are relative to.
@@ -417,7 +428,7 @@ pub struct TypeckTables<'tcx> {
417428

418429
/// All the existential types that are restricted to concrete types
419430
/// by this function
420-
pub concrete_existential_types: FxHashMap<DefId, Ty<'tcx>>,
431+
pub concrete_existential_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
421432

422433
/// Given the closure ID this map provides the list of UpvarIDs used by it.
423434
/// The upvarID contains the HIR node ID and it also contains the full path

src/librustc/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, ke
7474
pub use self::context::{Lift, TypeckTables, CtxtInterners};
7575
pub use self::context::{
7676
UserTypeAnnotationIndex, UserType, CanonicalUserType,
77-
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
77+
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy,
7878
};
7979

8080
pub use self::instance::{Instance, InstanceDef};

src/librustc_typeck/check/writeback.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,17 +567,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
567567
}
568568
}
569569

570+
let new = ty::ResolvedOpaqueTy {
571+
concrete_type: definition_ty,
572+
substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(),
573+
};
574+
570575
let old = self.tables
571576
.concrete_existential_types
572-
.insert(def_id, definition_ty);
577+
.insert(def_id, new);
573578
if let Some(old) = old {
574-
if old != definition_ty {
579+
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
575580
span_bug!(
576581
span,
577582
"visit_opaque_types tried to write \
578-
different types for the same existential type: {:?}, {:?}, {:?}",
583+
different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
579584
def_id,
580585
definition_ty,
586+
opaque_defn,
581587
old,
582588
);
583589
}

src/librustc_typeck/collect.rs

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ use middle::resolve_lifetime as rl;
2323
use middle::weak_lang_items;
2424
use rustc::mir::mono::Linkage;
2525
use rustc::ty::query::Providers;
26-
use rustc::ty::subst::Substs;
26+
use rustc::ty::subst::{Subst, Substs};
2727
use rustc::ty::util::Discr;
2828
use rustc::ty::util::IntTypeExt;
29+
use rustc::ty::subst::UnpackedKind;
2930
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
3031
use rustc::ty::{ReprOptions, ToPredicate};
3132
use rustc::util::captures::Captures;
@@ -1193,7 +1194,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
11931194
tcx.typeck_tables_of(owner)
11941195
.concrete_existential_types
11951196
.get(&def_id)
1196-
.cloned()
1197+
.map(|opaque| opaque.concrete_type)
11971198
.unwrap_or_else(|| {
11981199
// This can occur if some error in the
11991200
// owner fn prevented us from populating
@@ -1325,7 +1326,13 @@ fn find_existential_constraints<'a, 'tcx>(
13251326
struct ConstraintLocator<'a, 'tcx: 'a> {
13261327
tcx: TyCtxt<'a, 'tcx, 'tcx>,
13271328
def_id: DefId,
1328-
found: Option<(Span, ty::Ty<'tcx>)>,
1329+
// First found type span, actual type, mapping from the existential type's generic
1330+
// parameters to the concrete type's generic parameters
1331+
//
1332+
// The mapping is an index for each use site of a generic parameter in the concrete type
1333+
//
1334+
// The indices index into the generic parameters on the existential type.
1335+
found: Option<(Span, ty::Ty<'tcx>, Vec<usize>)>,
13291336
}
13301337

13311338
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
@@ -1340,13 +1347,50 @@ fn find_existential_constraints<'a, 'tcx>(
13401347
.tcx
13411348
.typeck_tables_of(def_id)
13421349
.concrete_existential_types
1343-
.get(&self.def_id)
1344-
.cloned();
1345-
if let Some(ty) = ty {
1350+
.get(&self.def_id);
1351+
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
13461352
// FIXME(oli-obk): trace the actual span from inference to improve errors
13471353
let span = self.tcx.def_span(def_id);
1348-
if let Some((prev_span, prev_ty)) = self.found {
1349-
let mut ty = ty.walk().fuse();
1354+
// used to quickly look up the position of a generic parameter
1355+
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
1356+
// skip binder is ok, since we only use this to find generic parameters and their
1357+
// positions.
1358+
for subst in substs.iter() {
1359+
if let UnpackedKind::Type(ty) = subst.unpack() {
1360+
if let ty::Param(p) = ty.sty {
1361+
let idx = index_map.len();
1362+
if index_map.insert(p, idx).is_some() {
1363+
// there was already an entry for `p`, meaning a generic parameter
1364+
// was used twice
1365+
self.tcx.sess.span_err(
1366+
span,
1367+
&format!("defining existential type use restricts existential \
1368+
type by using the generic parameter `{}` twice", p.name),
1369+
);
1370+
return;
1371+
}
1372+
} else {
1373+
self.tcx.sess.delay_span_bug(
1374+
span,
1375+
&format!(
1376+
"non-defining exist ty use in defining scope: {:?}, {:?}",
1377+
concrete_type, substs,
1378+
),
1379+
);
1380+
}
1381+
}
1382+
}
1383+
// compute the index within the existential type for each generic parameter used in
1384+
// the concrete type
1385+
let indices = concrete_type
1386+
.subst(self.tcx, substs)
1387+
.walk()
1388+
.filter_map(|t| match &t.sty {
1389+
ty::Param(p) => Some(*index_map.get(p).unwrap()),
1390+
_ => None,
1391+
}).collect();
1392+
if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
1393+
let mut ty = concrete_type.walk().fuse();
13501394
let mut prev_ty = prev_ty.walk().fuse();
13511395
let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) {
13521396
// type parameters are equal to any other type parameter for the purpose of
@@ -1359,13 +1403,21 @@ fn find_existential_constraints<'a, 'tcx>(
13591403
// found different concrete types for the existential type
13601404
let mut err = self.tcx.sess.struct_span_err(
13611405
span,
1362-
"defining existential type use differs from previous",
1406+
"concrete type differs from previous defining existential type use",
1407+
);
1408+
err.span_note(prev_span, "previous use here");
1409+
err.emit();
1410+
} else if indices != *prev_indices {
1411+
// found "same" concrete types, but the generic parameter order differs
1412+
let mut err = self.tcx.sess.struct_span_err(
1413+
span,
1414+
"concrete type's generic parameters differ from previous defining use",
13631415
);
13641416
err.span_note(prev_span, "previous use here");
13651417
err.emit();
13661418
}
13671419
} else {
1368-
self.found = Some((span, ty));
1420+
self.found = Some((span, concrete_type, indices));
13691421
}
13701422
}
13711423
}
@@ -1424,7 +1476,7 @@ fn find_existential_constraints<'a, 'tcx>(
14241476
}
14251477

14261478
match locator.found {
1427-
Some((_, ty)) => ty,
1479+
Some((_, ty, _)) => ty,
14281480
None => {
14291481
let span = tcx.def_span(def_id);
14301482
tcx.sess.span_err(span, "could not find defining uses");

src/test/ui/existential_types/different_defining_uses.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ fn foo() -> Foo {
99
""
1010
}
1111

12-
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
12+
fn bar() -> Foo { //~ ERROR concrete type differs from previous
1313
42i32
1414
}

src/test/ui/existential_types/different_defining_uses.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
error: defining existential type use differs from previous
1+
error: concrete type differs from previous defining existential type use
22
--> $DIR/different_defining_uses.rs:12:1
33
|
4-
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
4+
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
55
LL | | 42i32
66
LL | | }
77
| |_^

src/test/ui/existential_types/different_defining_uses_never_type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ fn foo() -> Foo {
99
""
1010
}
1111

12-
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
12+
fn bar() -> Foo { //~ ERROR concrete type differs from previous
1313
panic!()
1414
}
1515

16-
fn boo() -> Foo { //~ ERROR defining existential type use differs from previous
16+
fn boo() -> Foo { //~ ERROR concrete type differs from previous
1717
loop {}
1818
}

src/test/ui/existential_types/different_defining_uses_never_type.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
error: defining existential type use differs from previous
1+
error: concrete type differs from previous defining existential type use
22
--> $DIR/different_defining_uses_never_type.rs:12:1
33
|
4-
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
4+
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
55
LL | | panic!()
66
LL | | }
77
| |_^
@@ -14,10 +14,10 @@ LL | | ""
1414
LL | | }
1515
| |_^
1616

17-
error: defining existential type use differs from previous
17+
error: concrete type differs from previous defining existential type use
1818
--> $DIR/different_defining_uses_never_type.rs:16:1
1919
|
20-
LL | / fn boo() -> Foo { //~ ERROR defining existential type use differs from previous
20+
LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous
2121
LL | | loop {}
2222
LL | | }
2323
| |_^

src/test/ui/existential_types/generic_different_defining_uses.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ fn my_iter<T>(t: T) -> MyIter<T> {
88
std::iter::once(t)
99
}
1010

11-
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
11+
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
1212
Some(t).into_iter()
1313
}

src/test/ui/existential_types/generic_different_defining_uses.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
error: defining existential type use differs from previous
1+
error: concrete type differs from previous defining existential type use
22
--> $DIR/generic_different_defining_uses.rs:11:1
33
|
4-
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
4+
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
55
LL | | Some(t).into_iter()
66
LL | | }
77
| |_^
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// compile-pass
21
#![feature(existential_type)]
32

43
use std::fmt::Debug;
@@ -7,7 +6,9 @@ fn main() {}
76

87
// test that unused generic parameters are ok
98
existential type Two<T, U>: Debug;
9+
//~^ could not find defining uses
1010

1111
fn one<T: Debug>(t: T) -> Two<T, T> {
12+
//~^ ERROR defining existential type use restricts existential type
1213
t
1314
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: defining existential type use restricts existential type by using the generic parameter `T` twice
2+
--> $DIR/generic_duplicate_param_use.rs:11:1
3+
|
4+
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
5+
LL | | //~^ ERROR defining existential type use restricts existential type
6+
LL | | t
7+
LL | | }
8+
| |_^
9+
10+
error: could not find defining uses
11+
--> $DIR/generic_duplicate_param_use.rs:8:1
12+
|
13+
LL | existential type Two<T, U>: Debug;
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: aborting due to 2 previous errors
17+

src/test/ui/existential_types/generic_duplicate_param_use2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// compile-pass
21
#![feature(existential_type)]
32

43
use std::fmt::Debug;
@@ -9,6 +8,7 @@ fn main() {}
98
existential type Two<T, U>: Debug;
109

1110
fn one<T: Debug>(t: T) -> Two<T, T> {
11+
//~^ defining existential type use restricts existential type
1212
t
1313
}
1414

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: defining existential type use restricts existential type by using the generic parameter `T` twice
2+
--> $DIR/generic_duplicate_param_use2.rs:10:1
3+
|
4+
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
5+
LL | | //~^ defining existential type use restricts existential type
6+
LL | | t
7+
LL | | }
8+
| |_^
9+
10+
error: aborting due to previous error
11+

src/test/ui/existential_types/generic_duplicate_param_use3.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// compile-pass
21
#![feature(existential_type)]
32

43
use std::fmt::Debug;
@@ -9,6 +8,7 @@ fn main() {}
98
existential type Two<T, U>: Debug;
109

1110
fn one<T: Debug>(t: T) -> Two<T, T> {
11+
//~^ defining existential type use restricts existential type
1212
t
1313
}
1414

@@ -17,5 +17,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
1717
}
1818

1919
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
20+
//~^ concrete type's generic parameters differ from previous defining use
2021
u
2122
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: defining existential type use restricts existential type by using the generic parameter `T` twice
2+
--> $DIR/generic_duplicate_param_use3.rs:10:1
3+
|
4+
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
5+
LL | | //~^ defining existential type use restricts existential type
6+
LL | | t
7+
LL | | }
8+
| |_^
9+
10+
error: concrete type's generic parameters differ from previous defining use
11+
--> $DIR/generic_duplicate_param_use3.rs:19:1
12+
|
13+
LL | / fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
14+
LL | | //~^ concrete type's generic parameters differ from previous defining use
15+
LL | | u
16+
LL | | }
17+
| |_^
18+
|
19+
note: previous use here
20+
--> $DIR/generic_duplicate_param_use3.rs:15:1
21+
|
22+
LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
23+
LL | | t
24+
LL | | }
25+
| |_^
26+
27+
error: aborting due to 2 previous errors
28+

0 commit comments

Comments
 (0)