Skip to content

Commit

Permalink
Rollup merge of rust-lang#121386 - oli-obk:no_higher_ranked_opaques, …
Browse files Browse the repository at this point in the history
…r=lcnr

test that we do not support higher-ranked regions in opaque type inference

We already do all the right checks in `check_opaque_type_parameter_valid`, and we have done so since at least 2 years.

I collected the tests from rust-lang#116935 and rust-lang#100503 and added some more

cc rust-lang#96146

r? `@lcnr`
  • Loading branch information
matthiaskrgr authored Feb 22, 2024
2 parents 490ee5a + e4622e0 commit 24e8155
Show file tree
Hide file tree
Showing 19 changed files with 455 additions and 34 deletions.
14 changes: 8 additions & 6 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
if prev.ty != ty {
let guar = ty.error_reported().err().unwrap_or_else(|| {
prev.report_mismatch(
&OpaqueHiddenType { ty, span: concrete_type.span },
opaque_type_key.def_id,
infcx.tcx,
)
.emit()
let (Ok(e) | Err(e)) = prev
.build_mismatch_error(
&OpaqueHiddenType { ty, span: concrete_type.span },
opaque_type_key.def_id,
infcx.tcx,
)
.map(|d| d.emit());
e
});
prev.ty = Ty::new_error(infcx.tcx, guar);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ fn sanity_check_found_hidden_type<'tcx>(
} else {
let span = tcx.def_span(key.def_id);
let other = ty::OpaqueHiddenType { ty: hidden_ty, span };
Err(ty.report_mismatch(&other, key.def_id, tcx).emit())
Err(ty.build_mismatch_error(&other, key.def_id, tcx)?.emit())
}
}

Expand Down
43 changes: 25 additions & 18 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty)
&& !(concrete_type, hidden).references_error()
{
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
if concrete_type.ty != tcx.erase_regions(hidden.ty) {
if let Ok(d) = hidden.build_mismatch_error(&concrete_type, def_id, tcx) {
d.emit();
}
}
}
}
Expand Down Expand Up @@ -134,10 +134,10 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty)
&& !(concrete_type, hidden).references_error()
{
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
if concrete_type.ty != tcx.erase_regions(hidden.ty) {
if let Ok(d) = hidden.build_mismatch_error(&concrete_type, def_id, tcx) {
d.emit();
}
}
}
}
Expand Down Expand Up @@ -287,8 +287,10 @@ impl TaitConstraintLocator<'_> {
if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
if concrete_type.ty != prev.ty {
let (Ok(guar) | Err(guar)) = prev
.build_mismatch_error(&concrete_type, self.def_id, self.tcx)
.map(|d| d.emit());
prev.ty = Ty::new_error(self.tcx, guar);
}
} else {
Expand Down Expand Up @@ -361,11 +363,13 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true),
);
if let Some(prev) = &mut hir_opaque_ty {
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
prev.report_mismatch(&concrete_type, def_id, tcx).stash(
tcx.def_span(opaque_type_key.def_id),
StashKey::OpaqueHiddenTypeMismatch,
);
if concrete_type.ty != prev.ty {
if let Ok(d) = prev.build_mismatch_error(&concrete_type, def_id, tcx) {
d.stash(
tcx.def_span(opaque_type_key.def_id),
StashKey::OpaqueHiddenTypeMismatch,
);
}
}
} else {
hir_opaque_ty = Some(concrete_type);
Expand Down Expand Up @@ -436,9 +440,12 @@ impl RpitConstraintChecker<'_> {

debug!(?concrete_type, "found constraint");

if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error()
{
self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
if concrete_type.ty != self.found.ty {
if let Ok(d) =
self.found.build_mismatch_error(&concrete_type, self.def_id, self.tcx)
{
d.emit();
}
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,12 +589,16 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
&& last_opaque_ty.ty != hidden_type.ty
{
assert!(!self.fcx.next_trait_solver());
hidden_type
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
.stash(
if let Ok(d) = hidden_type.build_mismatch_error(
&last_opaque_ty,
opaque_type_key.def_id,
self.tcx(),
) {
d.stash(
self.tcx().def_span(opaque_type_key.def_id),
StashKey::OpaqueHiddenTypeMismatch,
);
}
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,31 +840,32 @@ pub struct OpaqueHiddenType<'tcx> {
}

impl<'tcx> OpaqueHiddenType<'tcx> {
pub fn report_mismatch(
pub fn build_mismatch_error(
&self,
other: &Self,
opaque_def_id: LocalDefId,
tcx: TyCtxt<'tcx>,
) -> DiagnosticBuilder<'tcx> {
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed> {
if let Some(diag) = tcx
.sess
.dcx()
.steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
{
diag.cancel();
}
(self.ty, other.ty).error_reported()?;
// Found different concrete types for the opaque type.
let sub_diag = if self.span == other.span {
TypeMismatchReason::ConflictType { span: self.span }
} else {
TypeMismatchReason::PreviousUse { span: self.span }
};
tcx.dcx().create_err(OpaqueHiddenTypeMismatch {
Ok(tcx.dcx().create_err(OpaqueHiddenTypeMismatch {
self_ty: self.ty,
other_ty: other.ty,
other_span: other.span,
sub: sub_diag,
})
}))
}

#[instrument(level = "debug", skip(tcx), ret)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
query_key: ParamEnvAnd<'tcx, Self>,
infcx: &InferCtxt<'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
span: Span,
) -> Result<
(
Self::QueryResponse,
Expand All @@ -118,7 +119,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't

let InferOk { value, obligations } = infcx
.instantiate_nll_query_response_and_region_obligations(
&ObligationCause::dummy(),
&ObligationCause::dummy_with_span(span),
old_param_env,
&canonical_var_values,
canonical_result,
Expand Down Expand Up @@ -160,7 +161,7 @@ where

let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| {
infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}"))
})?;

Expand All @@ -178,6 +179,7 @@ where
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
infcx,
&mut region_constraints,
span,
) {
Ok(((), _, new, certainty)) => {
obligations.extend(new);
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/generic-associated-types/issue-90014-tait2.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
error[E0792]: expected generic lifetime parameter, found `'a`
--> $DIR/issue-90014-tait2.rs:27:9
|
LL | type Fut<'a> = impl Future<Output = ()>;
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | Box::new((async { () },))
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

Expand Down
25 changes: 25 additions & 0 deletions tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Regression test for #97099.
// This was an ICE because `impl Sized` captures the lifetime 'a.

// check-fail

trait Trait<E> {
type Assoc;
}

struct Foo;

impl<'a> Trait<&'a ()> for Foo {
type Assoc = ();
}

fn foo() -> impl for<'a> Trait<&'a ()> {
Foo
}

fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> {
foo()
//~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
}

fn main() {}
13 changes: 13 additions & 0 deletions tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/higher-ranked-regions-diag.rs:21:5
|
LL | fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> {
| -- ---------- opaque type defined here
| |
| hidden type `<impl for<'a> Trait<&'a ()> as Trait<&'a ()>>::Assoc` captures the lifetime `'a` as defined here
LL | foo()
| ^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0700`.
82 changes: 82 additions & 0 deletions tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Basic tests for opaque type inference under for<_> binders.

// check-fail

#![feature(type_alias_impl_trait)]

trait Trait<'a> {
type Ty;
}
impl<'a, T> Trait<'a> for T {
type Ty = &'a ();
}

mod basic_pass {
use super::*;
type Opq<'a> = impl Sized + 'a;
fn test() -> impl for<'a> Trait<'a, Ty = Opq<'a>> {}
//~^ ERROR: expected generic lifetime parameter, found `'a`
}

mod capture_rpit {
use super::*;
fn test() -> impl for<'a> Trait<'a, Ty = impl Sized> {}
//~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
}

mod capture_tait {
use super::*;
type Opq0 = impl Sized;
type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0>;
type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
fn test() -> Opq2 {}
//~^ ERROR hidden type for `capture_tait::Opq0` captures lifetime that does not appear in bounds
}

mod capture_tait_complex_pass {
use super::*;
type Opq0<'a> = impl Sized;
type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'b>>; // <- Note 'b
type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
fn test() -> Opq2 {}
//~^ ERROR: expected generic lifetime parameter, found `'a`
}

// Same as the above, but make sure that different placeholder regions are not equal.
mod capture_tait_complex_fail {
use super::*;
type Opq0<'a> = impl Sized;
type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a>>; // <- Note 'a
type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
fn test() -> Opq2 {}
//~^ ERROR hidden type for `capture_tait_complex_fail::Opq0<'a>` captures lifetime that does not appear in bounds
}

// non-defining use because 'static is used.
mod constrain_fail0 {
use super::*;
type Opq0<'a, 'b> = impl Sized;
fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {}
//~^ ERROR non-defining opaque type use in defining scope
//~| ERROR: expected generic lifetime parameter, found `'a`
}

// non-defining use because generic lifetime is used multiple times.
mod constrain_fail {
use super::*;
type Opq0<'a, 'b> = impl Sized;
fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {}
//~^ ERROR non-defining opaque type use in defining scope
//~| ERROR: expected generic lifetime parameter, found `'a`
}

mod constrain_pass {
use super::*;
type Opq0<'a, 'b> = impl Sized;
type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a, 'b>>;
type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
fn test() -> Opq2 {}
//~^ ERROR: expected generic lifetime parameter, found `'a`
}

fn main() {}
Loading

0 comments on commit 24e8155

Please sign in to comment.