From 64c2a09414aaf09f7a8b34bf54f163ad06db84c9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 08:56:10 +0000 Subject: [PATCH] Ensure opaque types can't have themselves as a hidden type with incompatible lifetimes --- compiler/rustc_borrowck/src/type_check/mod.rs | 43 ++++++++++++++++++- .../src/type_check/relate_tys.rs | 4 +- tests/ui/impl-trait/issue-100075-2.rs | 4 +- tests/ui/impl-trait/issue-100075-2.stderr | 21 ++++++--- tests/ui/impl-trait/issue-100075.rs | 2 +- tests/ui/impl-trait/issue-100075.stderr | 19 +++++--- .../different_args_considered_equal.rs | 14 ++++++ .../different_args_considered_equal.stderr | 10 +++++ 8 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/different_args_considered_equal.rs create mode 100644 tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 71b54a761a2be..0b1a24b330ed1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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}; @@ -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` has a hidden type of `Foo>` + // 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(); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 78609a482ed22..ea166dd0c4743 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -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, @@ -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? diff --git a/tests/ui/impl-trait/issue-100075-2.rs b/tests/ui/impl-trait/issue-100075-2.rs index cf059af192512..498e537e48b9a 100644 --- a/tests/ui/impl-trait/issue-100075-2.rs +++ b/tests/ui/impl-trait/issue-100075-2.rs @@ -1,7 +1,7 @@ fn opaque(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)] diff --git a/tests/ui/impl-trait/issue-100075-2.stderr b/tests/ui/impl-trait/issue-100075-2.stderr index b3b6967750705..46e5795ea7c07 100644 --- a/tests/ui/impl-trait/issue-100075-2.stderr +++ b/tests/ui/impl-trait/issue-100075-2.stderr @@ -3,22 +3,29 @@ warning: function cannot return without recursing | LL | fn opaque(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) -> 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` + | + = note: expected opaque type `impl Sized` (type parameter `T`) + found opaque type `impl Sized` (`Option`) + = 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`. diff --git a/tests/ui/impl-trait/issue-100075.rs b/tests/ui/impl-trait/issue-100075.rs index ea30abb4855f3..fc733d157cc30 100644 --- a/tests/ui/impl-trait/issue-100075.rs +++ b/tests/ui/impl-trait/issue-100075.rs @@ -11,9 +11,9 @@ fn maybe( } fn _g(t: &'static T) -> &'static impl Marker { - //~^ ERROR cannot resolve opaque type if let Some(t) = maybe(t) { return _g(t); + //~^ ERROR mismatched types } todo!() } diff --git a/tests/ui/impl-trait/issue-100075.stderr b/tests/ui/impl-trait/issue-100075.stderr index 7596348923693..facaa5e28a24d 100644 --- a/tests/ui/impl-trait/issue-100075.stderr +++ b/tests/ui/impl-trait/issue-100075.stderr @@ -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: &'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`. diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs b/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs new file mode 100644 index 0000000000000..a311b1e57d021 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs @@ -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> { + None::> + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr b/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr new file mode 100644 index 0000000000000..afdb09e6c6cba --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr @@ -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> { + | -- lifetime `'a` defined here +LL | None::> + | ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error +