Skip to content

Commit

Permalink
Ensure opaque types can't have themselves as a hidden type with incom…
Browse files Browse the repository at this point in the history
…patible lifetimes
  • Loading branch information
oli-obk committed Apr 11, 2024
1 parent 6df1ffe commit 64c2a09
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 19 deletions.
43 changes: 42 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, TypeTrace,
};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
Expand Down Expand Up @@ -245,6 +245,47 @@ pub(crate) fn type_check<'mir, 'tcx>(
}
});

// If the hidden type is the opaque type itself (with potentially different args), we can
// check that the hidden type's args are the same, without worrying about defining new
// opaque types or producing new obligations beyond lifetime obligations
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
&& alias_ty.def_id == opaque_type_key.def_id.into()
{
if let Err(terr) = checker.eq_args(
opaque_type_key.args,
alias_ty.args,
Locations::All(hidden_type.span),
ConstraintCategory::OpaqueType,
) {
// Recursive opaque type: An opaque type `Foo<T>` has a hidden type of `Foo<Vec<T>>`
// This can happen with recursive function calls.
let cause = ObligationCause::dummy_with_span(hidden_type.span);
let guar = infcx
.err_ctxt()
.report_and_explain_type_error(
TypeTrace::types(
&cause,
true,
Ty::new_opaque(
infcx.tcx,
opaque_type_key.def_id.into(),
opaque_type_key.args,
),
hidden_type.ty,
),
terr,
)
.emit();
return (
opaque_type_key,
OpaqueHiddenType {
ty: Ty::new_error(infcx.tcx, guar),
span: hidden_type.span,
},
);
}
}

(opaque_type_key, hidden_type)
})
.collect();
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
b: ty::GenericArgsRef<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
) -> Result<(), NoSolution> {
) -> RelateResult<'tcx, ()> {
NllTypeRelating::new(
self,
locations,
Expand All @@ -61,7 +61,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}

pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
struct NllTypeRelating<'me, 'bccx, 'tcx> {
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,

/// Where (and why) is this relation taking place?
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/issue-100075-2.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
fn opaque<T>(t: T) -> impl Sized {
//~^ ERROR cannot resolve opaque type
//~| WARNING function cannot return without recursing
//~^ WARNING function cannot return without recursing
opaque(Some(t))
//~^ ERROR mismatched types
}

#[allow(dead_code)]
Expand Down
21 changes: 14 additions & 7 deletions tests/ui/impl-trait/issue-100075-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@ warning: function cannot return without recursing
|
LL | fn opaque<T>(t: T) -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
...
LL |
LL | opaque(Some(t))
| --------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default

error[E0720]: cannot resolve opaque type
--> $DIR/issue-100075-2.rs:1:23
error[E0308]: mismatched types
--> $DIR/issue-100075-2.rs:3:5
|
LL | fn opaque<T>(t: T) -> impl Sized {
| ^^^^^^^^^^ recursive opaque type
...
| ----------
| |
| the expected opaque type
| the found opaque type
LL |
LL | opaque(Some(t))
| --------------- returning here with type `impl Sized`
| ^^^^^^^^^^^^^^^ expected type parameter `T`, found `Option<T>`
|
= note: expected opaque type `impl Sized` (type parameter `T`)
found opaque type `impl Sized` (`Option<T>`)
= note: distinct uses of `impl Trait` result in different opaque types

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

For more information about this error, try `rustc --explain E0720`.
For more information about this error, try `rustc --explain E0308`.
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/issue-100075.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ fn maybe<T>(
}

fn _g<T>(t: &'static T) -> &'static impl Marker {
//~^ ERROR cannot resolve opaque type
if let Some(t) = maybe(t) {
return _g(t);
//~^ ERROR mismatched types
}
todo!()
}
Expand Down
19 changes: 13 additions & 6 deletions tests/ui/impl-trait/issue-100075.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
error[E0720]: cannot resolve opaque type
--> $DIR/issue-100075.rs:13:37
error[E0308]: mismatched types
--> $DIR/issue-100075.rs:15:16
|
LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
| ^^^^^^^^^^^ recursive opaque type
...
| -----------
| |
| the expected opaque type
| the found opaque type
LL | if let Some(t) = maybe(t) {
LL | return _g(t);
| ----- returning here with type `&impl Marker`
| ^^^^^ expected type parameter `T`, found `&T`
|
= note: expected opaque type `impl Marker` (type parameter `T`)
found opaque type `impl Marker` (`&T`)
= note: distinct uses of `impl Trait` result in different opaque types

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0720`.
For more information about this error, try `rustc --explain E0308`.
14 changes: 14 additions & 0 deletions tests/ui/type-alias-impl-trait/different_args_considered_equal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(type_alias_impl_trait)]

pub type Opaque<'a> = impl Sized;

fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
a
}

fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
None::<Opaque<'static>>
//~^ ERROR lifetime may not live long enough
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/different_args_considered_equal.rs:10:5
|
LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
| -- lifetime `'a` defined here
LL | None::<Opaque<'static>>
| ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`

error: aborting due to 1 previous error

0 comments on commit 64c2a09

Please sign in to comment.