Skip to content

Commit

Permalink
Prevent defining opaque types in nested items
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Mar 15, 2023
1 parent d715644 commit 733e444
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 14 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ hir_analysis_trait_object_declared_with_no_traits =
hir_analysis_opaque_type_constrained_but_not_in_sig = opaque type constrained without being represented in the signature
.item_label = this item must mention the opaque type in its signature or where bounds
hir_analysis_opaque_type_constrained_but_not_in_sibling = opaque type constrained in nested item
.item_label = this item is not a sibling of the opaque type
hir_analysis_missing_type_params =
the type {$parameterCount ->
[one] parameter
Expand Down
72 changes: 61 additions & 11 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use rustc_span::{sym, Span, DUMMY_SP};

use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty};
use crate::errors::{OpaqueTypeConstrainedButNotInSig, UnconstrainedOpaqueType};
use crate::errors::{
OpaqueTypeConstrainedButNotInSig, OpaqueTypeConstrainedInNonSibling, UnconstrainedOpaqueType,
};

/// Computes the relevant generic parameter for a potential generic const argument.
///
Expand Down Expand Up @@ -640,13 +642,20 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
if let Err(item_def_id) =
if let Err((item_def_id, sibling)) =
may_define_opaque_type(self.tcx, item_def_id, self.def_id, concrete_type.span)
{
self.tcx.sess.emit_err(OpaqueTypeConstrainedButNotInSig {
span: concrete_type.span,
item_span: self.tcx.def_span(item_def_id),
});
if sibling {
self.tcx.sess.emit_err(OpaqueTypeConstrainedButNotInSig {
span: concrete_type.span,
item_span: self.tcx.def_span(item_def_id),
});
} else {
self.tcx.sess.emit_err(OpaqueTypeConstrainedInNonSibling {
span: concrete_type.span,
item_span: self.tcx.def_span(item_def_id),
});
}
}
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
Expand Down Expand Up @@ -766,8 +775,27 @@ fn may_define_opaque_type<'tcx>(
def_id: LocalDefId,
opaque_def_id: LocalDefId,
span: Span,
) -> Result<(), LocalDefId> {
if tcx.is_descendant_of(opaque_def_id.to_def_id(), def_id.to_def_id()) {
) -> Result<(), (LocalDefId, bool)> {
let mut parent = tcx.local_parent(opaque_def_id);
loop {
trace!(?parent);
match tcx.def_kind(parent) {
DefKind::AssocTy | DefKind::TyAlias => {
parent = tcx.local_parent(parent);
break;
}
// Skip nested opaque types
DefKind::OpaqueTy => {
parent = tcx.local_parent(parent);
}
def_kind => {
trace!(?def_kind);
return Err((def_id, false));
}
}
}
trace!(?parent);
if parent == def_id {
// If the opaque type is defined in the body of a function, that function
// may constrain the opaque type since it can't mention it in bounds.
return Ok(());
Expand All @@ -777,9 +805,31 @@ fn may_define_opaque_type<'tcx>(
return may_define_opaque_type(tcx, tcx.local_parent(def_id), opaque_def_id, span);
}

let mut item_parent = tcx.local_parent(def_id);
while item_parent != parent {
trace!(?item_parent);
match tcx.def_kind(item_parent) {
// Skip impls, to allow methods to constrain opaque types from the surrounding module.
DefKind::Impl { .. } | DefKind::Trait => {
item_parent = tcx.local_parent(item_parent);
}
// Skip modules, to allow constraining opaque types in child modules
DefKind::Mod => {
item_parent = tcx.local_parent(item_parent);
}
def_kind => {
trace!(?def_kind);
break;
}
}
}

if item_parent != parent {
return Err((def_id, false));
}

let param_env = tcx.param_env(def_id);

trace!(parent = ?tcx.parent(opaque_def_id.to_def_id()));
fn has_tait<'tcx>(
val: impl TypeVisitable<TyCtxt<'tcx>>,
opaque_def_id: LocalDefId,
Expand Down Expand Up @@ -874,7 +924,7 @@ fn may_define_opaque_type<'tcx>(
let tait_in_where_bounds =
has_tait(tcx.predicates_of(def_id.to_def_id()).predicates, opaque_def_id, tcx, param_env);
if tcx.features().type_alias_impl_trait_in_where_bounds {
if tait_in_where_bounds { Ok(()) } else { Err(def_id) }
if tait_in_where_bounds { Ok(()) } else { Err((def_id, true)) }
} else {
if tait_in_where_bounds {
feature_err(
Expand All @@ -885,7 +935,7 @@ fn may_define_opaque_type<'tcx>(
)
.emit();
}
Err(def_id)
Err((def_id, true))
}
}

Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ pub struct OpaqueTypeConstrainedButNotInSig {
#[label(hir_analysis_item_label)]
pub item_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_opaque_type_constrained_but_not_in_sibling)]
pub struct OpaqueTypeConstrainedInNonSibling {
#[primary_span]
pub span: Span,
#[label(hir_analysis_item_label)]
pub item_span: Span,
}

pub struct MissingTypeParams {
pub span: Span,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ where
// Type in const path
const {
pub struct Foo;
fn foo() -> Type5 {
Foo
}
let _: Type5 = Foo;
};

// Type in impl path
Expand Down
30 changes: 30 additions & 0 deletions tests/ui/type-alias-impl-trait/defining-use-item-child.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![feature(type_alias_impl_trait)]

fn main() {}

type Foo = impl std::fmt::Display;

fn bar() {
pub fn foo() -> Foo {
"foo"
//~^ ERROR: opaque type constrained in nested item
}
}

fn baz() -> Foo {
pub fn foo() -> Foo {
"foo"
//~^ ERROR: opaque type constrained in nested item
}
"baz"
}

struct Bak {
x: [u8; {
fn blob() -> Foo {
"blob"
//~^ ERROR: opaque type constrained in nested item
}
5
}],
}
26 changes: 26 additions & 0 deletions tests/ui/type-alias-impl-trait/defining-use-item-child.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: opaque type constrained in nested item
--> $DIR/defining-use-item-child.rs:9:9
|
LL | pub fn foo() -> Foo {
| ------------------- this item is not a sibling of the opaque type
LL | "foo"
| ^^^^^

error: opaque type constrained in nested item
--> $DIR/defining-use-item-child.rs:16:9
|
LL | pub fn foo() -> Foo {
| ------------------- this item is not a sibling of the opaque type
LL | "foo"
| ^^^^^

error: opaque type constrained in nested item
--> $DIR/defining-use-item-child.rs:25:13
|
LL | fn blob() -> Foo {
| ---------------- this item is not a sibling of the opaque type
LL | "blob"
| ^^^^^^

error: aborting due to 3 previous errors

0 comments on commit 733e444

Please sign in to comment.