Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tait must be constrained if in sig #113169

Merged
merged 3 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions compiler/rustc_codegen_cranelift/example/issue-72793.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@

#![feature(type_alias_impl_trait)]

trait T {
type Item;
}
mod helper {
pub trait T {
type Item;
}

type Alias<'a> = impl T<Item = &'a ()>;
pub type Alias<'a> = impl T<Item = &'a ()>;

struct S;
impl<'a> T for &'a S {
type Item = &'a ();
}
struct S;
impl<'a> T for &'a S {
type Item = &'a ();
}

fn filter_positive<'a>() -> Alias<'a> {
&S
pub fn filter_positive<'a>() -> Alias<'a> {
&S
}
}
use helper::*;

fn with_positive(fun: impl Fn(Alias<'_>)) {
fun(filter_positive());
Expand Down
27 changes: 16 additions & 11 deletions compiler/rustc_data_structures/src/obligation_forest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ pub enum ProcessResult<O, E> {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct ObligationTreeId(usize);

type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;

pub struct ObligationForest<O: ForestObligation> {
/// The list of obligations. In between calls to [Self::process_obligations],
/// this list only contains nodes in the `Pending` or `Waiting` state.
Expand Down Expand Up @@ -310,18 +308,25 @@ pub struct Error<O, E> {
pub backtrace: Vec<O>,
}

impl<O: ForestObligation> ObligationForest<O> {
pub fn new() -> ObligationForest<O> {
ObligationForest {
nodes: vec![],
done_cache: Default::default(),
active_cache: Default::default(),
reused_node_vec: vec![],
obligation_tree_id_generator: (0..).map(ObligationTreeId),
error_cache: Default::default(),
mod helper {
use super::*;
pub type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
impl<O: ForestObligation> ObligationForest<O> {
pub fn new() -> ObligationForest<O> {
ObligationForest {
nodes: vec![],
done_cache: Default::default(),
active_cache: Default::default(),
reused_node_vec: vec![],
obligation_tree_id_generator: (0..).map(ObligationTreeId),
error_cache: Default::default(),
}
}
}
}
use helper::*;

impl<O: ForestObligation> ObligationForest<O> {
/// Returns the total number of nodes in the forest that have not
/// yet been fully resolved.
pub fn len(&self) -> usize {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0792.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type Foo<T> = impl std::fmt::Debug;
fn foo<U>() -> Foo<U> {
5u32
}

fn main() {}
```

This means that no matter the generic parameter to `foo`,
Expand All @@ -57,4 +59,6 @@ type Foo<T: Debug> = impl Debug;
fn foo<U: Debug>() -> Foo<U> {
Vec::<U>::new()
}

fn main() {}
```
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
.note = this item must mention the opaque type in its signature in order to be able to register hidden types

hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature
.note = consider moving the opaque type's declaration and defining uses into a separate module
.opaque = this opaque type is in the signature

hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`

hir_analysis_too_large_static = extern static is too large for the current architecture
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};

use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
use crate::errors::{TaitForwardCompat, TaitForwardCompat2, TypeOf, UnconstrainedOpaqueType};

pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
Expand Down Expand Up @@ -229,13 +229,14 @@ impl TaitConstraintLocator<'_> {
return;
}

let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);

let mut constrained = false;
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
continue;
}
constrained = true;
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);

if !opaque_types_defined_by.contains(&self.def_id) {
self.tcx.dcx().emit_err(TaitForwardCompat {
Expand All @@ -259,6 +260,16 @@ impl TaitConstraintLocator<'_> {

if !constrained {
debug!("no constraints in typeck results");
if opaque_types_defined_by.contains(&self.def_id) {
self.tcx.dcx().emit_err(TaitForwardCompat2 {
span: self
.tcx
.def_ident_span(item_def_id)
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
opaque_type_span: self.tcx.def_span(self.def_id),
opaque_type: self.tcx.def_path_str(self.def_id),
});
}
Comment on lines +263 to +272
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now the only relevant diff in the compiler. Everything else is expected fallout

return;
};

Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,17 @@ pub struct TaitForwardCompat {
pub item_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_tait_forward_compat2)]
#[note]
pub struct TaitForwardCompat2 {
#[primary_span]
pub span: Span,
#[note(hir_analysis_opaque)]
pub opaque_type_span: Span,
pub opaque_type: String,
}

pub struct MissingTypeParams {
pub span: Span,
pub def_span: Span,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ declare_lint! {
/// fn test() -> impl Trait<Assoc = Tait> {
/// 42
/// }
///
/// fn main() {}
/// ```
///
/// {{produces}}
Expand Down
151 changes: 81 additions & 70 deletions compiler/rustc_middle/src/mir/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,6 @@ pub struct Terminator<'tcx> {
pub kind: TerminatorKind<'tcx>,
}

pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;

impl<'tcx> Terminator<'tcx> {
#[inline]
pub fn successors(&self) -> Successors<'_> {
Expand Down Expand Up @@ -407,81 +404,95 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
}
}

#[inline]
pub fn successors(&self) -> Successors<'_> {
use self::TerminatorKind::*;
match *self {
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
| Yield { resume: ref t, drop: Some(u), .. }
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
slice::from_ref(t).into_iter().copied().chain(Some(u))
}
Goto { target: ref t }
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
| Call { target: Some(ref t), unwind: _, .. }
| Yield { resume: ref t, drop: None, .. }
| Drop { target: ref t, unwind: _, .. }
| Assert { target: ref t, unwind: _, .. }
| FalseUnwind { real_target: ref t, unwind: _ } => {
slice::from_ref(t).into_iter().copied().chain(None)
}
UnwindResume
| UnwindTerminate(_)
| CoroutineDrop
| Return
| Unreachable
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
targets.iter().copied().chain(Some(u))
}
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
FalseEdge { ref real_target, imaginary_target } => {
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
pub use helper::*;

mod helper {
use super::*;
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;
impl<'tcx> TerminatorKind<'tcx> {
#[inline]
pub fn successors(&self) -> Successors<'_> {
use self::TerminatorKind::*;
match *self {
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
| Yield { resume: ref t, drop: Some(u), .. }
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
slice::from_ref(t).into_iter().copied().chain(Some(u))
}
Goto { target: ref t }
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
| Call { target: Some(ref t), unwind: _, .. }
| Yield { resume: ref t, drop: None, .. }
| Drop { target: ref t, unwind: _, .. }
| Assert { target: ref t, unwind: _, .. }
| FalseUnwind { real_target: ref t, unwind: _ } => {
slice::from_ref(t).into_iter().copied().chain(None)
}
UnwindResume
| UnwindTerminate(_)
| CoroutineDrop
| Return
| Unreachable
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
targets.iter().copied().chain(Some(u))
}
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
FalseEdge { ref real_target, imaginary_target } => {
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
}
}
}
}

#[inline]
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
use self::TerminatorKind::*;
match *self {
Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } => {
slice::from_mut(t).into_iter().chain(Some(u))
}
Goto { target: ref mut t }
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
| Call { target: Some(ref mut t), unwind: _, .. }
| Yield { resume: ref mut t, drop: None, .. }
| Drop { target: ref mut t, unwind: _, .. }
| Assert { target: ref mut t, unwind: _, .. }
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
slice::from_mut(t).into_iter().chain(None)
}
UnwindResume
| UnwindTerminate(_)
| CoroutineDrop
| Return
| Unreachable
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
targets.iter_mut().chain(Some(u))
}
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
#[inline]
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
use self::TerminatorKind::*;
match *self {
Call {
target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), ..
}
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| FalseUnwind {
real_target: ref mut t,
unwind: UnwindAction::Cleanup(ref mut u),
} => slice::from_mut(t).into_iter().chain(Some(u)),
Goto { target: ref mut t }
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
| Call { target: Some(ref mut t), unwind: _, .. }
| Yield { resume: ref mut t, drop: None, .. }
| Drop { target: ref mut t, unwind: _, .. }
| Assert { target: ref mut t, unwind: _, .. }
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
slice::from_mut(t).into_iter().chain(None)
}
UnwindResume
| UnwindTerminate(_)
| CoroutineDrop
| Return
| Unreachable
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
targets.iter_mut().chain(Some(u))
}
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
}
}
}
}
}

impl<'tcx> TerminatorKind<'tcx> {
#[inline]
pub fn unwind(&self) -> Option<&UnwindAction> {
match *self {
Expand Down
41 changes: 41 additions & 0 deletions library/core/src/internal_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,47 @@ macro_rules! forward_ref_op_assign {
}
}

/// Create a zero-size type similar to a closure type, but named.
macro_rules! impl_fn_for_zst {
($(
$( #[$attr: meta] )*
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
$body: block;
)+) => {
$(
$( #[$attr] )*
struct $Name;

impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
$body
}
}

impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call_mut(
&mut self,
($( $arg, )*): ($( $ArgTy, )*)
) -> $ReturnTy {
Fn::call(&*self, ($( $arg, )*))
}
}

impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
type Output = $ReturnTy;

#[inline]
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
Fn::call(&self, ($( $arg, )*))
}
}
)+
}
}

/// A macro for defining `#[cfg]` if-else statements.
///
/// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade
Expand Down
Loading
Loading