Skip to content

Commit 64c2a09

Browse files
committed
Ensure opaque types can't have themselves as a hidden type with incompatible lifetimes
1 parent 6df1ffe commit 64c2a09

File tree

8 files changed

+98
-19
lines changed

8 files changed

+98
-19
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
1818
use rustc_infer::infer::region_constraints::RegionConstraintData;
1919
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2020
use rustc_infer::infer::{
21-
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
21+
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, TypeTrace,
2222
};
2323
use rustc_middle::mir::tcx::PlaceTy;
2424
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@@ -245,6 +245,47 @@ pub(crate) fn type_check<'mir, 'tcx>(
245245
}
246246
});
247247

248+
// If the hidden type is the opaque type itself (with potentially different args), we can
249+
// check that the hidden type's args are the same, without worrying about defining new
250+
// opaque types or producing new obligations beyond lifetime obligations
251+
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
252+
&& alias_ty.def_id == opaque_type_key.def_id.into()
253+
{
254+
if let Err(terr) = checker.eq_args(
255+
opaque_type_key.args,
256+
alias_ty.args,
257+
Locations::All(hidden_type.span),
258+
ConstraintCategory::OpaqueType,
259+
) {
260+
// Recursive opaque type: An opaque type `Foo<T>` has a hidden type of `Foo<Vec<T>>`
261+
// This can happen with recursive function calls.
262+
let cause = ObligationCause::dummy_with_span(hidden_type.span);
263+
let guar = infcx
264+
.err_ctxt()
265+
.report_and_explain_type_error(
266+
TypeTrace::types(
267+
&cause,
268+
true,
269+
Ty::new_opaque(
270+
infcx.tcx,
271+
opaque_type_key.def_id.into(),
272+
opaque_type_key.args,
273+
),
274+
hidden_type.ty,
275+
),
276+
terr,
277+
)
278+
.emit();
279+
return (
280+
opaque_type_key,
281+
OpaqueHiddenType {
282+
ty: Ty::new_error(infcx.tcx, guar),
283+
span: hidden_type.span,
284+
},
285+
);
286+
}
287+
}
288+
248289
(opaque_type_key, hidden_type)
249290
})
250291
.collect();

compiler/rustc_borrowck/src/type_check/relate_tys.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
4848
b: ty::GenericArgsRef<'tcx>,
4949
locations: Locations,
5050
category: ConstraintCategory<'tcx>,
51-
) -> Result<(), NoSolution> {
51+
) -> RelateResult<'tcx, ()> {
5252
NllTypeRelating::new(
5353
self,
5454
locations,
@@ -61,7 +61,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
6161
}
6262
}
6363

64-
pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
64+
struct NllTypeRelating<'me, 'bccx, 'tcx> {
6565
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
6666

6767
/// Where (and why) is this relation taking place?

tests/ui/impl-trait/issue-100075-2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
fn opaque<T>(t: T) -> impl Sized {
2-
//~^ ERROR cannot resolve opaque type
3-
//~| WARNING function cannot return without recursing
2+
//~^ WARNING function cannot return without recursing
43
opaque(Some(t))
4+
//~^ ERROR mismatched types
55
}
66

77
#[allow(dead_code)]

tests/ui/impl-trait/issue-100075-2.stderr

+14-7
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,29 @@ warning: function cannot return without recursing
33
|
44
LL | fn opaque<T>(t: T) -> impl Sized {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
6-
...
6+
LL |
77
LL | opaque(Some(t))
88
| --------------- recursive call site
99
|
1010
= help: a `loop` may express intention better if this is on purpose
1111
= note: `#[warn(unconditional_recursion)]` on by default
1212

13-
error[E0720]: cannot resolve opaque type
14-
--> $DIR/issue-100075-2.rs:1:23
13+
error[E0308]: mismatched types
14+
--> $DIR/issue-100075-2.rs:3:5
1515
|
1616
LL | fn opaque<T>(t: T) -> impl Sized {
17-
| ^^^^^^^^^^ recursive opaque type
18-
...
17+
| ----------
18+
| |
19+
| the expected opaque type
20+
| the found opaque type
21+
LL |
1922
LL | opaque(Some(t))
20-
| --------------- returning here with type `impl Sized`
23+
| ^^^^^^^^^^^^^^^ expected type parameter `T`, found `Option<T>`
24+
|
25+
= note: expected opaque type `impl Sized` (type parameter `T`)
26+
found opaque type `impl Sized` (`Option<T>`)
27+
= note: distinct uses of `impl Trait` result in different opaque types
2128

2229
error: aborting due to 1 previous error; 1 warning emitted
2330

24-
For more information about this error, try `rustc --explain E0720`.
31+
For more information about this error, try `rustc --explain E0308`.

tests/ui/impl-trait/issue-100075.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ fn maybe<T>(
1111
}
1212

1313
fn _g<T>(t: &'static T) -> &'static impl Marker {
14-
//~^ ERROR cannot resolve opaque type
1514
if let Some(t) = maybe(t) {
1615
return _g(t);
16+
//~^ ERROR mismatched types
1717
}
1818
todo!()
1919
}
+13-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
error[E0720]: cannot resolve opaque type
2-
--> $DIR/issue-100075.rs:13:37
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-100075.rs:15:16
33
|
44
LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
5-
| ^^^^^^^^^^^ recursive opaque type
6-
...
5+
| -----------
6+
| |
7+
| the expected opaque type
8+
| the found opaque type
9+
LL | if let Some(t) = maybe(t) {
710
LL | return _g(t);
8-
| ----- returning here with type `&impl Marker`
11+
| ^^^^^ expected type parameter `T`, found `&T`
12+
|
13+
= note: expected opaque type `impl Marker` (type parameter `T`)
14+
found opaque type `impl Marker` (`&T`)
15+
= note: distinct uses of `impl Trait` result in different opaque types
916

1017
error: aborting due to 1 previous error
1118

12-
For more information about this error, try `rustc --explain E0720`.
19+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
pub type Opaque<'a> = impl Sized;
4+
5+
fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
6+
a
7+
}
8+
9+
fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
10+
None::<Opaque<'static>>
11+
//~^ ERROR lifetime may not live long enough
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/different_args_considered_equal.rs:10:5
3+
|
4+
LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
5+
| -- lifetime `'a` defined here
6+
LL | None::<Opaque<'static>>
7+
| ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)