Skip to content

Commit 02c7a59

Browse files
committed
Auto merge of #113169 - oli-obk:tait_must_be_constrained_if_in_sig, r=lcnr
Tait must be constrained if in sig r? `@compiler-errors` kind of reverts #62423, but that PR only removed cycles in cases that we want to forbid now anyway. see https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/lcnr.20oli.20meeting/near/370712246 for related discussion and motivating example a TAIT showing up in a signature doesn't just mean it can register a hidden type, but that it must. This is the [design the types team decided upon](https://hackmd.io/QOsEaEJtQK-XDS_xN4UyQA#Proposal-preferred) for the following reasons * avoids a hypothetical situation where getting smarter in trait solving could cause new cycle errors or new inference errors to show up, where today something is treated as opaque. * avoids having the situation where a (minor?) change to a function body causes an error, because its TAIT usage suddenly isn't "opaque enough" anymore. * avoids having to explain why in some cases you need to put a Tait into a tiny module together with its defining usages. Now you basically gotta always do this, the moment a Tait is in a signature that isn't in the defining scope. * avoids false-cycle errors * anything diverging from this pattern needs to either * move the TAIT declaration and defining function into their own helper sub module * use the attributes we'll provide in the future to explicitly opt in or out of being in the defining scope fixes #117861 reverts #125362 cc `@Nilstrieb` `@joboet`
2 parents bdb1b7f + 85f2eca commit 02c7a59

File tree

123 files changed

+1637
-742
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

123 files changed

+1637
-742
lines changed

compiler/rustc_codegen_cranelift/example/issue-72793.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,23 @@
22

33
#![feature(type_alias_impl_trait)]
44

5-
trait T {
6-
type Item;
7-
}
5+
mod helper {
6+
pub trait T {
7+
type Item;
8+
}
89

9-
type Alias<'a> = impl T<Item = &'a ()>;
10+
pub type Alias<'a> = impl T<Item = &'a ()>;
1011

11-
struct S;
12-
impl<'a> T for &'a S {
13-
type Item = &'a ();
14-
}
12+
struct S;
13+
impl<'a> T for &'a S {
14+
type Item = &'a ();
15+
}
1516

16-
fn filter_positive<'a>() -> Alias<'a> {
17-
&S
17+
pub fn filter_positive<'a>() -> Alias<'a> {
18+
&S
19+
}
1820
}
21+
use helper::*;
1922

2023
fn with_positive(fun: impl Fn(Alias<'_>)) {
2124
fun(filter_positive());

compiler/rustc_data_structures/src/obligation_forest/mod.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ pub enum ProcessResult<O, E> {
146146
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
147147
struct ObligationTreeId(usize);
148148

149-
type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
150-
151149
pub struct ObligationForest<O: ForestObligation> {
152150
/// The list of obligations. In between calls to [Self::process_obligations],
153151
/// this list only contains nodes in the `Pending` or `Waiting` state.
@@ -310,18 +308,25 @@ pub struct Error<O, E> {
310308
pub backtrace: Vec<O>,
311309
}
312310

313-
impl<O: ForestObligation> ObligationForest<O> {
314-
pub fn new() -> ObligationForest<O> {
315-
ObligationForest {
316-
nodes: vec![],
317-
done_cache: Default::default(),
318-
active_cache: Default::default(),
319-
reused_node_vec: vec![],
320-
obligation_tree_id_generator: (0..).map(ObligationTreeId),
321-
error_cache: Default::default(),
311+
mod helper {
312+
use super::*;
313+
pub type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
314+
impl<O: ForestObligation> ObligationForest<O> {
315+
pub fn new() -> ObligationForest<O> {
316+
ObligationForest {
317+
nodes: vec![],
318+
done_cache: Default::default(),
319+
active_cache: Default::default(),
320+
reused_node_vec: vec![],
321+
obligation_tree_id_generator: (0..).map(ObligationTreeId),
322+
error_cache: Default::default(),
323+
}
322324
}
323325
}
326+
}
327+
use helper::*;
324328

329+
impl<O: ForestObligation> ObligationForest<O> {
325330
/// Returns the total number of nodes in the forest that have not
326331
/// yet been fully resolved.
327332
pub fn len(&self) -> usize {

compiler/rustc_error_codes/src/error_codes/E0792.md

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ type Foo<T> = impl std::fmt::Debug;
3939
fn foo<U>() -> Foo<U> {
4040
5u32
4141
}
42+
43+
fn main() {}
4244
```
4345

4446
This means that no matter the generic parameter to `foo`,
@@ -57,4 +59,6 @@ type Foo<T: Debug> = impl Debug;
5759
fn foo<U: Debug>() -> Foo<U> {
5860
Vec::<U>::new()
5961
}
62+
63+
fn main() {}
6064
```

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime
460460
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
461461
.note = this item must mention the opaque type in its signature in order to be able to register hidden types
462462
463+
hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature
464+
.note = consider moving the opaque type's declaration and defining uses into a separate module
465+
.opaque = this opaque type is in the signature
466+
463467
hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
464468
465469
hir_analysis_too_large_static = extern static is too large for the current architecture

compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::hir::nested_filter;
88
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
99
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
1010

11-
use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
11+
use crate::errors::{TaitForwardCompat, TaitForwardCompat2, TypeOf, UnconstrainedOpaqueType};
1212

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

232+
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
233+
232234
let mut constrained = false;
233235
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
234236
if opaque_type_key.def_id != self.def_id {
235237
continue;
236238
}
237239
constrained = true;
238-
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
239240

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

260261
if !constrained {
261262
debug!("no constraints in typeck results");
263+
if opaque_types_defined_by.contains(&self.def_id) {
264+
self.tcx.dcx().emit_err(TaitForwardCompat2 {
265+
span: self
266+
.tcx
267+
.def_ident_span(item_def_id)
268+
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
269+
opaque_type_span: self.tcx.def_span(self.def_id),
270+
opaque_type: self.tcx.def_path_str(self.def_id),
271+
});
272+
}
262273
return;
263274
};
264275

compiler/rustc_hir_analysis/src/errors.rs

+11
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,17 @@ pub struct TaitForwardCompat {
390390
pub item_span: Span,
391391
}
392392

393+
#[derive(Diagnostic)]
394+
#[diag(hir_analysis_tait_forward_compat2)]
395+
#[note]
396+
pub struct TaitForwardCompat2 {
397+
#[primary_span]
398+
pub span: Span,
399+
#[note(hir_analysis_opaque)]
400+
pub opaque_type_span: Span,
401+
pub opaque_type: String,
402+
}
403+
393404
pub struct MissingTypeParams {
394405
pub span: Span,
395406
pub def_span: Span,

compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ declare_lint! {
4646
/// fn test() -> impl Trait<Assoc = Tait> {
4747
/// 42
4848
/// }
49+
///
50+
/// fn main() {}
4951
/// ```
5052
///
5153
/// {{produces}}

compiler/rustc_middle/src/mir/terminator.rs

+81-70
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,6 @@ pub struct Terminator<'tcx> {
377377
pub kind: TerminatorKind<'tcx>,
378378
}
379379

380-
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
381-
pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;
382-
383380
impl<'tcx> Terminator<'tcx> {
384381
#[inline]
385382
pub fn successors(&self) -> Successors<'_> {
@@ -407,81 +404,95 @@ impl<'tcx> TerminatorKind<'tcx> {
407404
pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
408405
TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
409406
}
407+
}
410408

411-
#[inline]
412-
pub fn successors(&self) -> Successors<'_> {
413-
use self::TerminatorKind::*;
414-
match *self {
415-
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
416-
| Yield { resume: ref t, drop: Some(u), .. }
417-
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
418-
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
419-
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
420-
slice::from_ref(t).into_iter().copied().chain(Some(u))
421-
}
422-
Goto { target: ref t }
423-
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
424-
| Call { target: Some(ref t), unwind: _, .. }
425-
| Yield { resume: ref t, drop: None, .. }
426-
| Drop { target: ref t, unwind: _, .. }
427-
| Assert { target: ref t, unwind: _, .. }
428-
| FalseUnwind { real_target: ref t, unwind: _ } => {
429-
slice::from_ref(t).into_iter().copied().chain(None)
430-
}
431-
UnwindResume
432-
| UnwindTerminate(_)
433-
| CoroutineDrop
434-
| Return
435-
| Unreachable
436-
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
437-
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
438-
targets.iter().copied().chain(Some(u))
439-
}
440-
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
441-
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
442-
FalseEdge { ref real_target, imaginary_target } => {
443-
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
409+
pub use helper::*;
410+
411+
mod helper {
412+
use super::*;
413+
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
414+
pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;
415+
impl<'tcx> TerminatorKind<'tcx> {
416+
#[inline]
417+
pub fn successors(&self) -> Successors<'_> {
418+
use self::TerminatorKind::*;
419+
match *self {
420+
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
421+
| Yield { resume: ref t, drop: Some(u), .. }
422+
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
423+
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
424+
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
425+
slice::from_ref(t).into_iter().copied().chain(Some(u))
426+
}
427+
Goto { target: ref t }
428+
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
429+
| Call { target: Some(ref t), unwind: _, .. }
430+
| Yield { resume: ref t, drop: None, .. }
431+
| Drop { target: ref t, unwind: _, .. }
432+
| Assert { target: ref t, unwind: _, .. }
433+
| FalseUnwind { real_target: ref t, unwind: _ } => {
434+
slice::from_ref(t).into_iter().copied().chain(None)
435+
}
436+
UnwindResume
437+
| UnwindTerminate(_)
438+
| CoroutineDrop
439+
| Return
440+
| Unreachable
441+
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
442+
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
443+
targets.iter().copied().chain(Some(u))
444+
}
445+
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
446+
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
447+
FalseEdge { ref real_target, imaginary_target } => {
448+
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
449+
}
444450
}
445451
}
446-
}
447452

448-
#[inline]
449-
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
450-
use self::TerminatorKind::*;
451-
match *self {
452-
Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
453-
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
454-
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
455-
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
456-
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } => {
457-
slice::from_mut(t).into_iter().chain(Some(u))
458-
}
459-
Goto { target: ref mut t }
460-
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
461-
| Call { target: Some(ref mut t), unwind: _, .. }
462-
| Yield { resume: ref mut t, drop: None, .. }
463-
| Drop { target: ref mut t, unwind: _, .. }
464-
| Assert { target: ref mut t, unwind: _, .. }
465-
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
466-
slice::from_mut(t).into_iter().chain(None)
467-
}
468-
UnwindResume
469-
| UnwindTerminate(_)
470-
| CoroutineDrop
471-
| Return
472-
| Unreachable
473-
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
474-
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
475-
targets.iter_mut().chain(Some(u))
476-
}
477-
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
478-
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
479-
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
480-
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
453+
#[inline]
454+
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
455+
use self::TerminatorKind::*;
456+
match *self {
457+
Call {
458+
target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), ..
459+
}
460+
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
461+
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
462+
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
463+
| FalseUnwind {
464+
real_target: ref mut t,
465+
unwind: UnwindAction::Cleanup(ref mut u),
466+
} => slice::from_mut(t).into_iter().chain(Some(u)),
467+
Goto { target: ref mut t }
468+
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
469+
| Call { target: Some(ref mut t), unwind: _, .. }
470+
| Yield { resume: ref mut t, drop: None, .. }
471+
| Drop { target: ref mut t, unwind: _, .. }
472+
| Assert { target: ref mut t, unwind: _, .. }
473+
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
474+
slice::from_mut(t).into_iter().chain(None)
475+
}
476+
UnwindResume
477+
| UnwindTerminate(_)
478+
| CoroutineDrop
479+
| Return
480+
| Unreachable
481+
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
482+
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
483+
targets.iter_mut().chain(Some(u))
484+
}
485+
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
486+
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
487+
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
488+
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
489+
}
481490
}
482491
}
483492
}
493+
}
484494

495+
impl<'tcx> TerminatorKind<'tcx> {
485496
#[inline]
486497
pub fn unwind(&self) -> Option<&UnwindAction> {
487498
match *self {

library/core/src/internal_macros.rs

+41
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,47 @@ macro_rules! forward_ref_op_assign {
8080
}
8181
}
8282

83+
/// Create a zero-size type similar to a closure type, but named.
84+
macro_rules! impl_fn_for_zst {
85+
($(
86+
$( #[$attr: meta] )*
87+
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
88+
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
89+
$body: block;
90+
)+) => {
91+
$(
92+
$( #[$attr] )*
93+
struct $Name;
94+
95+
impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
96+
#[inline]
97+
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
98+
$body
99+
}
100+
}
101+
102+
impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
103+
#[inline]
104+
extern "rust-call" fn call_mut(
105+
&mut self,
106+
($( $arg, )*): ($( $ArgTy, )*)
107+
) -> $ReturnTy {
108+
Fn::call(&*self, ($( $arg, )*))
109+
}
110+
}
111+
112+
impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
113+
type Output = $ReturnTy;
114+
115+
#[inline]
116+
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
117+
Fn::call(&self, ($( $arg, )*))
118+
}
119+
}
120+
)+
121+
}
122+
}
123+
83124
/// A macro for defining `#[cfg]` if-else statements.
84125
///
85126
/// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade

0 commit comments

Comments
 (0)