Auto merge of #119837 - matthiaskrgr:rollup-l2olpad, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #115046 (Use version-sorting for all sorting) - #118915 (Add some comments, add `can_define_opaque_ty` check to `try_normalize_ty_recur`) - #119006 (Fix is_global special address handling) - #119637 (Pass LLVM error message back to pass wrapper.) - #119715 (Exhaustiveness: abort on type error) - #119763 (Cleanup things in and around `Diagnostic`) - #119788 (change function name in comments) - #119790 (Fix all_trait* methods to return all traits available in StableMIR) - #119803 (Silence some follow-up errors [1/x]) - #119804 (Stabilize mutex_unpoison feature) - #119832 (Meta: Add project const traits to triagebot config) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
65b323b168
54 changed files with 690 additions and 303 deletions
|
@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
|
|
||||||
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
||||||
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
|
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||||
let default = tcx.object_lifetime_default(param.def_id);
|
let default = tcx.object_lifetime_default(param.def_id);
|
||||||
|
|
||||||
let re_static = tcx.lifetimes.re_static;
|
let re_static = tcx.lifetimes.re_static;
|
||||||
|
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
|
|
||||||
has_dyn = true;
|
has_dyn = true;
|
||||||
|
|
||||||
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
|
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
|
||||||
} else {
|
} else {
|
||||||
arg
|
arg
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,7 +394,7 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
|
||||||
let level = match item.map(|i| &i.kind) {
|
let level = match item.map(|i| &i.kind) {
|
||||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||||
// stable user code (#94508).
|
// stable user code (#94508).
|
||||||
Some(ast::ItemKind::MacCall(_)) => Level::Warning(None),
|
Some(ast::ItemKind::MacCall(_)) => Level::Warning,
|
||||||
_ => Level::Error,
|
_ => Level::Error,
|
||||||
};
|
};
|
||||||
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
|
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
|
||||||
|
|
|
@ -417,7 +417,7 @@ fn report_inline_asm(
|
||||||
}
|
}
|
||||||
let level = match level {
|
let level = match level {
|
||||||
llvm::DiagnosticLevel::Error => Level::Error,
|
llvm::DiagnosticLevel::Error => Level::Error,
|
||||||
llvm::DiagnosticLevel::Warning => Level::Warning(None),
|
llvm::DiagnosticLevel::Warning => Level::Warning,
|
||||||
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
||||||
};
|
};
|
||||||
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
|
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
|
||||||
|
|
|
@ -1847,14 +1847,9 @@ impl SharedEmitterMain {
|
||||||
dcx.emit_diagnostic(d);
|
dcx.emit_diagnostic(d);
|
||||||
}
|
}
|
||||||
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
|
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
|
||||||
let err_level = match level {
|
assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
|
||||||
Level::Error => Level::Error,
|
|
||||||
Level::Warning(_) => Level::Warning(None),
|
|
||||||
Level::Note => Level::Note,
|
|
||||||
_ => bug!("Invalid inline asm diagnostic level"),
|
|
||||||
};
|
|
||||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
|
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
|
||||||
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), err_level, msg);
|
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, msg);
|
||||||
|
|
||||||
// If the cookie is 0 then we don't have span information.
|
// If the cookie is 0 then we don't have span information.
|
||||||
if cookie != 0 {
|
if cookie != 0 {
|
||||||
|
|
|
@ -87,7 +87,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
|
||||||
fn annotation_type_for_level(level: Level) -> AnnotationType {
|
fn annotation_type_for_level(level: Level) -> AnnotationType {
|
||||||
match level {
|
match level {
|
||||||
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
|
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
|
||||||
Level::Warning(_) => AnnotationType::Warning,
|
Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
|
||||||
Level::Note | Level::OnceNote => AnnotationType::Note,
|
Level::Note | Level::OnceNote => AnnotationType::Note,
|
||||||
Level::Help | Level::OnceHelp => AnnotationType::Help,
|
Level::Help | Level::OnceHelp => AnnotationType::Help,
|
||||||
// FIXME(#59346): Not sure how to map this level
|
// FIXME(#59346): Not sure how to map this level
|
||||||
|
|
|
@ -152,7 +152,6 @@ pub enum DiagnosticId {
|
||||||
name: String,
|
name: String,
|
||||||
/// Indicates whether this lint should show up in cargo's future breakage report.
|
/// Indicates whether this lint should show up in cargo's future breakage report.
|
||||||
has_future_breakage: bool,
|
has_future_breakage: bool,
|
||||||
is_force_warn: bool,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +247,8 @@ impl Diagnostic {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
Level::Warning(_)
|
Level::ForceWarning(_)
|
||||||
|
| Level::Warning
|
||||||
| Level::Note
|
| Level::Note
|
||||||
| Level::OnceNote
|
| Level::OnceNote
|
||||||
| Level::Help
|
| Level::Help
|
||||||
|
@ -262,7 +262,7 @@ impl Diagnostic {
|
||||||
&mut self,
|
&mut self,
|
||||||
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||||
) {
|
) {
|
||||||
if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
|
if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) =
|
||||||
&mut self.level
|
&mut self.level
|
||||||
{
|
{
|
||||||
if expectation_id.is_stable() {
|
if expectation_id.is_stable() {
|
||||||
|
@ -292,8 +292,11 @@ impl Diagnostic {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_force_warn(&self) -> bool {
|
pub(crate) fn is_force_warn(&self) -> bool {
|
||||||
match self.code {
|
match self.level {
|
||||||
Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
|
Level::ForceWarning(_) => {
|
||||||
|
assert!(self.is_lint);
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,7 +475,7 @@ impl Diagnostic {
|
||||||
/// Add a warning attached to this diagnostic.
|
/// Add a warning attached to this diagnostic.
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
|
pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
|
||||||
self.sub(Level::Warning(None), msg, MultiSpan::new());
|
self.sub(Level::Warning, msg, MultiSpan::new());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +487,7 @@ impl Diagnostic {
|
||||||
sp: S,
|
sp: S,
|
||||||
msg: impl Into<SubdiagnosticMessage>,
|
msg: impl Into<SubdiagnosticMessage>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.sub(Level::Warning(None), msg, sp.into());
|
self.sub(Level::Warning, msg, sp.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ impl Emitter for JsonEmitter {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut diag| {
|
.map(|mut diag| {
|
||||||
if diag.level == crate::Level::Allow {
|
if diag.level == crate::Level::Allow {
|
||||||
diag.level = crate::Level::Warning(None);
|
diag.level = crate::Level::Warning;
|
||||||
}
|
}
|
||||||
FutureBreakageItem {
|
FutureBreakageItem {
|
||||||
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
|
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
|
||||||
|
|
|
@ -420,6 +420,7 @@ pub struct DiagCtxt {
|
||||||
/// as well as inconsistent state observation.
|
/// as well as inconsistent state observation.
|
||||||
struct DiagCtxtInner {
|
struct DiagCtxtInner {
|
||||||
flags: DiagCtxtFlags,
|
flags: DiagCtxtFlags,
|
||||||
|
|
||||||
/// The number of lint errors that have been emitted.
|
/// The number of lint errors that have been emitted.
|
||||||
lint_err_count: usize,
|
lint_err_count: usize,
|
||||||
/// The number of errors that have been emitted, including duplicates.
|
/// The number of errors that have been emitted, including duplicates.
|
||||||
|
@ -427,8 +428,13 @@ struct DiagCtxtInner {
|
||||||
/// This is not necessarily the count that's reported to the user once
|
/// This is not necessarily the count that's reported to the user once
|
||||||
/// compilation ends.
|
/// compilation ends.
|
||||||
err_count: usize,
|
err_count: usize,
|
||||||
warn_count: usize,
|
|
||||||
deduplicated_err_count: usize,
|
deduplicated_err_count: usize,
|
||||||
|
/// The warning count, used for a recap upon finishing
|
||||||
|
deduplicated_warn_count: usize,
|
||||||
|
/// Has this diagnostic context printed any diagnostics? (I.e. has
|
||||||
|
/// `self.emitter.emit_diagnostic()` been called?
|
||||||
|
has_printed: bool,
|
||||||
|
|
||||||
emitter: Box<DynEmitter>,
|
emitter: Box<DynEmitter>,
|
||||||
span_delayed_bugs: Vec<DelayedDiagnostic>,
|
span_delayed_bugs: Vec<DelayedDiagnostic>,
|
||||||
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
||||||
|
@ -455,9 +461,6 @@ struct DiagCtxtInner {
|
||||||
/// When `.abort_if_errors()` is called, these are also emitted.
|
/// When `.abort_if_errors()` is called, these are also emitted.
|
||||||
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
|
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
|
||||||
|
|
||||||
/// The warning count, used for a recap upon finishing
|
|
||||||
deduplicated_warn_count: usize,
|
|
||||||
|
|
||||||
future_breakage_diagnostics: Vec<Diagnostic>,
|
future_breakage_diagnostics: Vec<Diagnostic>,
|
||||||
|
|
||||||
/// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
|
/// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
|
||||||
|
@ -513,7 +516,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
|
||||||
(*f)(diag)
|
(*f)(diag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static TRACK_DIAGNOSTICS: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
|
pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
|
||||||
AtomicRef::new(&(default_track_diagnostic as _));
|
AtomicRef::new(&(default_track_diagnostic as _));
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
|
@ -547,8 +550,7 @@ impl Drop for DiagCtxtInner {
|
||||||
// instead of "require some error happened". Sadly that isn't ideal, as
|
// instead of "require some error happened". Sadly that isn't ideal, as
|
||||||
// lints can be `#[allow]`'d, potentially leading to this triggering.
|
// lints can be `#[allow]`'d, potentially leading to this triggering.
|
||||||
// Also, "good path" should be replaced with a better naming.
|
// Also, "good path" should be replaced with a better naming.
|
||||||
let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0;
|
if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
|
||||||
if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
|
|
||||||
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
|
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
|
||||||
self.flush_delayed(
|
self.flush_delayed(
|
||||||
bugs,
|
bugs,
|
||||||
|
@ -594,9 +596,9 @@ impl DiagCtxt {
|
||||||
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
||||||
lint_err_count: 0,
|
lint_err_count: 0,
|
||||||
err_count: 0,
|
err_count: 0,
|
||||||
warn_count: 0,
|
|
||||||
deduplicated_err_count: 0,
|
deduplicated_err_count: 0,
|
||||||
deduplicated_warn_count: 0,
|
deduplicated_warn_count: 0,
|
||||||
|
has_printed: false,
|
||||||
emitter,
|
emitter,
|
||||||
span_delayed_bugs: Vec::new(),
|
span_delayed_bugs: Vec::new(),
|
||||||
good_path_delayed_bugs: Vec::new(),
|
good_path_delayed_bugs: Vec::new(),
|
||||||
|
@ -647,10 +649,11 @@ impl DiagCtxt {
|
||||||
/// the overall count of emitted error diagnostics.
|
/// the overall count of emitted error diagnostics.
|
||||||
pub fn reset_err_count(&self) {
|
pub fn reset_err_count(&self) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
inner.lint_err_count = 0;
|
||||||
inner.err_count = 0;
|
inner.err_count = 0;
|
||||||
inner.warn_count = 0;
|
|
||||||
inner.deduplicated_err_count = 0;
|
inner.deduplicated_err_count = 0;
|
||||||
inner.deduplicated_warn_count = 0;
|
inner.deduplicated_warn_count = 0;
|
||||||
|
inner.has_printed = false;
|
||||||
|
|
||||||
// actually free the underlying memory (which `clear` would not do)
|
// actually free the underlying memory (which `clear` would not do)
|
||||||
inner.span_delayed_bugs = Default::default();
|
inner.span_delayed_bugs = Default::default();
|
||||||
|
@ -669,16 +672,11 @@ impl DiagCtxt {
|
||||||
let key = (span.with_parent(None), key);
|
let key = (span.with_parent(None), key);
|
||||||
|
|
||||||
if diag.is_error() {
|
if diag.is_error() {
|
||||||
if diag.level == Error && diag.is_lint {
|
if diag.is_lint {
|
||||||
inner.lint_err_count += 1;
|
inner.lint_err_count += 1;
|
||||||
} else {
|
} else {
|
||||||
inner.err_count += 1;
|
inner.err_count += 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Warnings are only automatically flushed if they're forced.
|
|
||||||
if diag.is_force_warn() {
|
|
||||||
inner.warn_count += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
|
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
|
||||||
|
@ -693,15 +691,11 @@ impl DiagCtxt {
|
||||||
let key = (span.with_parent(None), key);
|
let key = (span.with_parent(None), key);
|
||||||
let diag = inner.stashed_diagnostics.remove(&key)?;
|
let diag = inner.stashed_diagnostics.remove(&key)?;
|
||||||
if diag.is_error() {
|
if diag.is_error() {
|
||||||
if diag.level == Error && diag.is_lint {
|
if diag.is_lint {
|
||||||
inner.lint_err_count -= 1;
|
inner.lint_err_count -= 1;
|
||||||
} else {
|
} else {
|
||||||
inner.err_count -= 1;
|
inner.err_count -= 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if diag.is_force_warn() {
|
|
||||||
inner.warn_count -= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(DiagnosticBuilder::new_diagnostic(self, diag))
|
Some(DiagnosticBuilder::new_diagnostic(self, diag))
|
||||||
}
|
}
|
||||||
|
@ -738,7 +732,7 @@ impl DiagCtxt {
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||||
DiagnosticBuilder::new(self, Warning(None), msg)
|
DiagnosticBuilder::new(self, Warning, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a builder at the `Allow` level with the `msg`.
|
/// Construct a builder at the `Allow` level with the `msg`.
|
||||||
|
@ -1005,7 +999,7 @@ impl DiagCtxt {
|
||||||
(0, 0) => return,
|
(0, 0) => return,
|
||||||
(0, _) => inner
|
(0, _) => inner
|
||||||
.emitter
|
.emitter
|
||||||
.emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))),
|
.emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))),
|
||||||
(_, 0) => {
|
(_, 0) => {
|
||||||
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
|
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
|
||||||
}
|
}
|
||||||
|
@ -1094,7 +1088,7 @@ impl DiagCtxt {
|
||||||
&'a self,
|
&'a self,
|
||||||
warning: impl IntoDiagnostic<'a, ()>,
|
warning: impl IntoDiagnostic<'a, ()>,
|
||||||
) -> DiagnosticBuilder<'a, ()> {
|
) -> DiagnosticBuilder<'a, ()> {
|
||||||
warning.into_diagnostic(self, Warning(None))
|
warning.into_diagnostic(self, Warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -1241,21 +1235,17 @@ impl DiagCtxtInner {
|
||||||
for diag in diags {
|
for diag in diags {
|
||||||
// Decrement the count tracking the stash; emitting will increment it.
|
// Decrement the count tracking the stash; emitting will increment it.
|
||||||
if diag.is_error() {
|
if diag.is_error() {
|
||||||
if diag.level == Error && diag.is_lint {
|
if diag.is_lint {
|
||||||
self.lint_err_count -= 1;
|
self.lint_err_count -= 1;
|
||||||
} else {
|
} else {
|
||||||
self.err_count -= 1;
|
self.err_count -= 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if diag.is_force_warn() {
|
// Unless they're forced, don't flush stashed warnings when
|
||||||
self.warn_count -= 1;
|
// there are errors, to avoid causing warning overload. The
|
||||||
} else {
|
// stash would've been stolen already if it were important.
|
||||||
// Unless they're forced, don't flush stashed warnings when
|
if !diag.is_force_warn() && has_errors {
|
||||||
// there are errors, to avoid causing warning overload. The
|
continue;
|
||||||
// stash would've been stolen already if it were important.
|
|
||||||
if has_errors {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let reported_this = self.emit_diagnostic(diag);
|
let reported_this = self.emit_diagnostic(diag);
|
||||||
|
@ -1304,23 +1294,20 @@ impl DiagCtxtInner {
|
||||||
self.fulfilled_expectations.insert(expectation_id.normalize());
|
self.fulfilled_expectations.insert(expectation_id.normalize());
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(diagnostic.level, Warning(_))
|
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
|
||||||
&& !self.flags.can_emit_warnings
|
|
||||||
&& !diagnostic.is_force_warn()
|
|
||||||
{
|
|
||||||
if diagnostic.has_future_breakage() {
|
if diagnostic.has_future_breakage() {
|
||||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
|
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(diagnostic.level, Expect(_) | Allow) {
|
if matches!(diagnostic.level, Expect(_) | Allow) {
|
||||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
|
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut guaranteed = None;
|
let mut guaranteed = None;
|
||||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |mut diagnostic| {
|
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
|
||||||
if let Some(ref code) = diagnostic.code {
|
if let Some(ref code) = diagnostic.code {
|
||||||
self.emitted_diagnostic_codes.insert(code.clone());
|
self.emitted_diagnostic_codes.insert(code.clone());
|
||||||
}
|
}
|
||||||
|
@ -1359,12 +1346,13 @@ impl DiagCtxtInner {
|
||||||
self.emitter.emit_diagnostic(&diagnostic);
|
self.emitter.emit_diagnostic(&diagnostic);
|
||||||
if diagnostic.is_error() {
|
if diagnostic.is_error() {
|
||||||
self.deduplicated_err_count += 1;
|
self.deduplicated_err_count += 1;
|
||||||
} else if let Warning(_) = diagnostic.level {
|
} else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
|
||||||
self.deduplicated_warn_count += 1;
|
self.deduplicated_warn_count += 1;
|
||||||
}
|
}
|
||||||
|
self.has_printed = true;
|
||||||
}
|
}
|
||||||
if diagnostic.is_error() {
|
if diagnostic.is_error() {
|
||||||
if diagnostic.level == Error && diagnostic.is_lint {
|
if diagnostic.is_lint {
|
||||||
self.bump_lint_err_count();
|
self.bump_lint_err_count();
|
||||||
} else {
|
} else {
|
||||||
self.bump_err_count();
|
self.bump_err_count();
|
||||||
|
@ -1374,8 +1362,6 @@ impl DiagCtxtInner {
|
||||||
{
|
{
|
||||||
guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
|
guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.bump_warn_count();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1471,10 +1457,6 @@ impl DiagCtxtInner {
|
||||||
self.panic_if_treat_err_as_bug();
|
self.panic_if_treat_err_as_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bump_warn_count(&mut self) {
|
|
||||||
self.warn_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn panic_if_treat_err_as_bug(&self) {
|
fn panic_if_treat_err_as_bug(&self) {
|
||||||
if self.treat_err_as_bug() {
|
if self.treat_err_as_bug() {
|
||||||
match (
|
match (
|
||||||
|
@ -1562,14 +1544,17 @@ pub enum Level {
|
||||||
/// Its `EmissionGuarantee` is `ErrorGuaranteed`.
|
/// Its `EmissionGuarantee` is `ErrorGuaranteed`.
|
||||||
Error,
|
Error,
|
||||||
|
|
||||||
|
/// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
|
||||||
|
/// from finishing.
|
||||||
|
///
|
||||||
|
/// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this
|
||||||
|
/// should be `None`.
|
||||||
|
ForceWarning(Option<LintExpectationId>),
|
||||||
|
|
||||||
/// A warning about the code being compiled. Does not prevent compilation from finishing.
|
/// A warning about the code being compiled. Does not prevent compilation from finishing.
|
||||||
///
|
///
|
||||||
/// This [`LintExpectationId`] is used for expected lint diagnostics, which should
|
|
||||||
/// also emit a warning due to the `force-warn` flag. In all other cases this should
|
|
||||||
/// be `None`.
|
|
||||||
///
|
|
||||||
/// Its `EmissionGuarantee` is `()`.
|
/// Its `EmissionGuarantee` is `()`.
|
||||||
Warning(Option<LintExpectationId>),
|
Warning,
|
||||||
|
|
||||||
/// A message giving additional context. Rare, because notes are more commonly attached to other
|
/// A message giving additional context. Rare, because notes are more commonly attached to other
|
||||||
/// diagnostics such as errors.
|
/// diagnostics such as errors.
|
||||||
|
@ -1622,7 +1607,7 @@ impl Level {
|
||||||
Bug | DelayedBug | Fatal | Error => {
|
Bug | DelayedBug | Fatal | Error => {
|
||||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||||
}
|
}
|
||||||
Warning(_) => {
|
ForceWarning(_) | Warning => {
|
||||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||||
}
|
}
|
||||||
Note | OnceNote => {
|
Note | OnceNote => {
|
||||||
|
@ -1641,7 +1626,7 @@ impl Level {
|
||||||
match self {
|
match self {
|
||||||
Bug | DelayedBug => "error: internal compiler error",
|
Bug | DelayedBug => "error: internal compiler error",
|
||||||
Fatal | Error => "error",
|
Fatal | Error => "error",
|
||||||
Warning(_) => "warning",
|
ForceWarning(_) | Warning => "warning",
|
||||||
Note | OnceNote => "note",
|
Note | OnceNote => "note",
|
||||||
Help | OnceHelp => "help",
|
Help | OnceHelp => "help",
|
||||||
FailureNote => "failure-note",
|
FailureNote => "failure-note",
|
||||||
|
@ -1655,7 +1640,7 @@ impl Level {
|
||||||
|
|
||||||
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
||||||
match self {
|
match self {
|
||||||
Expect(id) | Warning(Some(id)) => Some(*id),
|
Expect(id) | ForceWarning(Some(id)) => Some(*id),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@ impl ToInternal<rustc_errors::Level> for Level {
|
||||||
fn to_internal(self) -> rustc_errors::Level {
|
fn to_internal(self) -> rustc_errors::Level {
|
||||||
match self {
|
match self {
|
||||||
Level::Error => rustc_errors::Level::Error,
|
Level::Error => rustc_errors::Level::Error,
|
||||||
Level::Warning => rustc_errors::Level::Warning(None),
|
Level::Warning => rustc_errors::Level::Warning,
|
||||||
Level::Note => rustc_errors::Level::Note,
|
Level::Note => rustc_errors::Level::Note,
|
||||||
Level::Help => rustc_errors::Level::Help,
|
Level::Help => rustc_errors::Level::Help,
|
||||||
_ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
|
_ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
|
||||||
|
|
|
@ -2405,6 +2405,39 @@ impl<'hir> Ty<'hir> {
|
||||||
my_visitor.visit_ty(self);
|
my_visitor.visit_ty(self);
|
||||||
my_visitor.0
|
my_visitor.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
|
||||||
|
/// use inference to provide suggestions for the appropriate type if possible.
|
||||||
|
pub fn is_suggestable_infer_ty(&self) -> bool {
|
||||||
|
fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
|
||||||
|
generic_args.iter().any(|arg| match arg {
|
||||||
|
GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
|
||||||
|
GenericArg::Infer(_) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
debug!(?self);
|
||||||
|
match &self.kind {
|
||||||
|
TyKind::Infer => true,
|
||||||
|
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
|
||||||
|
TyKind::Array(ty, length) => {
|
||||||
|
ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _))
|
||||||
|
}
|
||||||
|
TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
|
||||||
|
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
|
||||||
|
TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
|
||||||
|
TyKind::Path(QPath::TypeRelative(ty, segment)) => {
|
||||||
|
ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
|
||||||
|
}
|
||||||
|
TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => {
|
||||||
|
ty_opt.is_some_and(Self::is_suggestable_infer_ty)
|
||||||
|
|| segments
|
||||||
|
.iter()
|
||||||
|
.any(|segment| are_suggestable_generic_args(segment.args().args))
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not represented directly in the AST; referred to by name through a `ty_path`.
|
/// Not represented directly in the AST; referred to by name through a `ty_path`.
|
||||||
|
@ -2735,7 +2768,7 @@ pub enum FnRetTy<'hir> {
|
||||||
Return(&'hir Ty<'hir>),
|
Return(&'hir Ty<'hir>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnRetTy<'_> {
|
impl<'hir> FnRetTy<'hir> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -2743,6 +2776,15 @@ impl FnRetTy<'_> {
|
||||||
Self::Return(ref ty) => ty.span,
|
Self::Return(ref ty) => ty.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_infer_ret_ty(&self) -> Option<&'hir Ty<'hir>> {
|
||||||
|
if let Self::Return(ty) = self {
|
||||||
|
if ty.is_suggestable_infer_ty() {
|
||||||
|
return Some(*ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents `for<...>` binder before a closure
|
/// Represents `for<...>` binder before a closure
|
||||||
|
|
|
@ -642,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||||
tcx.ensure().generics_of(def_id);
|
tcx.ensure().generics_of(def_id);
|
||||||
tcx.ensure().type_of(def_id);
|
tcx.ensure().type_of(def_id);
|
||||||
tcx.ensure().predicates_of(def_id);
|
tcx.ensure().predicates_of(def_id);
|
||||||
if !is_suggestable_infer_ty(ty) {
|
if !ty.is_suggestable_infer_ty() {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_item(it);
|
visitor.visit_item(it);
|
||||||
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
|
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
|
||||||
|
@ -674,7 +674,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
||||||
hir::TraitItemKind::Const(ty, body_id) => {
|
hir::TraitItemKind::Const(ty, body_id) => {
|
||||||
tcx.ensure().type_of(def_id);
|
tcx.ensure().type_of(def_id);
|
||||||
if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
|
if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
|
||||||
&& !(is_suggestable_infer_ty(ty) && body_id.is_some())
|
&& !(ty.is_suggestable_infer_ty() && body_id.is_some())
|
||||||
{
|
{
|
||||||
// Account for `const C: _;`.
|
// Account for `const C: _;`.
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
|
@ -726,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
||||||
}
|
}
|
||||||
hir::ImplItemKind::Const(ty, _) => {
|
hir::ImplItemKind::Const(ty, _) => {
|
||||||
// Account for `const T: _ = ..;`
|
// Account for `const T: _ = ..;`
|
||||||
if !is_suggestable_infer_ty(ty) {
|
if !ty.is_suggestable_infer_ty() {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_impl_item(impl_item);
|
visitor.visit_impl_item(impl_item);
|
||||||
placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
|
placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
|
||||||
|
@ -1054,48 +1054,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
|
|
||||||
generic_args.iter().any(|arg| match arg {
|
|
||||||
hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
|
|
||||||
hir::GenericArg::Infer(_) => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
|
|
||||||
/// use inference to provide suggestions for the appropriate type if possible.
|
|
||||||
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
|
|
||||||
debug!(?ty);
|
|
||||||
use hir::TyKind::*;
|
|
||||||
match &ty.kind {
|
|
||||||
Infer => true,
|
|
||||||
Slice(ty) => is_suggestable_infer_ty(ty),
|
|
||||||
Array(ty, length) => {
|
|
||||||
is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
|
|
||||||
}
|
|
||||||
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
|
|
||||||
Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
|
|
||||||
OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
|
|
||||||
Path(hir::QPath::TypeRelative(ty, segment)) => {
|
|
||||||
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
|
|
||||||
}
|
|
||||||
Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
|
|
||||||
ty_opt.is_some_and(is_suggestable_infer_ty)
|
|
||||||
|| segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
|
|
||||||
if let hir::FnRetTy::Return(ty) = output {
|
|
||||||
if is_suggestable_infer_ty(ty) {
|
|
||||||
return Some(*ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(tcx))]
|
#[instrument(level = "debug", skip(tcx))]
|
||||||
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
|
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
|
||||||
use rustc_hir::Node::*;
|
use rustc_hir::Node::*;
|
||||||
|
@ -1188,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||||
) -> ty::PolyFnSig<'tcx> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||||
|
|
||||||
match get_infer_ret_ty(&sig.decl.output) {
|
match sig.decl.output.get_infer_ret_ty() {
|
||||||
Some(ty) => {
|
Some(ty) => {
|
||||||
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||||
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
||||||
|
|
|
@ -9,8 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
use super::bad_placeholder;
|
||||||
use super::ItemCtxt;
|
use super::ItemCtxt;
|
||||||
use super::{bad_placeholder, is_suggestable_infer_ty};
|
|
||||||
pub use opaque::test_opaque_hidden_types;
|
pub use opaque::test_opaque_hidden_types;
|
||||||
|
|
||||||
mod opaque;
|
mod opaque;
|
||||||
|
@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||||
}
|
}
|
||||||
TraitItemKind::Const(ty, body_id) => body_id
|
TraitItemKind::Const(ty, body_id) => body_id
|
||||||
.and_then(|body_id| {
|
.and_then(|body_id| {
|
||||||
is_suggestable_infer_ty(ty).then(|| {
|
ty.is_suggestable_infer_ty().then(|| {
|
||||||
infer_placeholder_type(
|
infer_placeholder_type(
|
||||||
tcx,
|
tcx,
|
||||||
def_id,
|
def_id,
|
||||||
|
@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||||
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
|
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
|
||||||
}
|
}
|
||||||
ImplItemKind::Const(ty, body_id) => {
|
ImplItemKind::Const(ty, body_id) => {
|
||||||
if is_suggestable_infer_ty(ty) {
|
if ty.is_suggestable_infer_ty() {
|
||||||
infer_placeholder_type(
|
infer_placeholder_type(
|
||||||
tcx,
|
tcx,
|
||||||
def_id,
|
def_id,
|
||||||
|
@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||||
|
|
||||||
Node::Item(item) => match item.kind {
|
Node::Item(item) => match item.kind {
|
||||||
ItemKind::Static(ty, .., body_id) => {
|
ItemKind::Static(ty, .., body_id) => {
|
||||||
if is_suggestable_infer_ty(ty) {
|
if ty.is_suggestable_infer_ty() {
|
||||||
infer_placeholder_type(
|
infer_placeholder_type(
|
||||||
tcx,
|
tcx,
|
||||||
def_id,
|
def_id,
|
||||||
|
@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::Const(ty, _, body_id) => {
|
ItemKind::Const(ty, _, body_id) => {
|
||||||
if is_suggestable_infer_ty(ty) {
|
if ty.is_suggestable_infer_ty() {
|
||||||
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
|
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
|
||||||
} else {
|
} else {
|
||||||
icx.to_ty(ty)
|
icx.to_ty(ty)
|
||||||
|
@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
|
// diagnostic stashing loses the information of whether something is a hard error.
|
||||||
|
Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error")
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut diag = bad_placeholder(tcx, vec![span], kind);
|
let mut diag = bad_placeholder(tcx, vec![span], kind);
|
||||||
|
@ -623,15 +625,9 @@ fn infer_placeholder_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.emit();
|
Ty::new_error(tcx, diag.emit())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
|
||||||
tcx.fold_regions(ty, |r, _| match *r {
|
|
||||||
ty::ReErased => tcx.lifetimes.re_static,
|
|
||||||
_ => r,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
|
fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
|
||||||
|
|
|
@ -134,6 +134,21 @@ impl TaitConstraintLocator<'_> {
|
||||||
debug!("no constraint: no typeck results");
|
debug!("no constraint: no typeck results");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
|
||||||
|
if hir_sig.output.get_infer_ret_ty().is_some() {
|
||||||
|
let guar = self.tcx.dcx().span_delayed_bug(
|
||||||
|
hir_sig.output.span(),
|
||||||
|
"inferring return types and opaque types do not mix well",
|
||||||
|
);
|
||||||
|
self.found = Some(ty::OpaqueHiddenType {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
ty: Ty::new_error(self.tcx, guar),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calling `mir_borrowck` can lead to cycle errors through
|
// Calling `mir_borrowck` can lead to cycle errors through
|
||||||
// const-checking, avoid calling it if we don't have to.
|
// const-checking, avoid calling it if we don't have to.
|
||||||
// ```rust
|
// ```rust
|
||||||
|
|
|
@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>(
|
||||||
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
|
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
|
||||||
|
|
||||||
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
||||||
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
|
let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
|
||||||
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
|
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
|
||||||
} else {
|
} else {
|
||||||
tcx.fn_sig(def_id).instantiate_identity()
|
tcx.fn_sig(def_id).instantiate_identity()
|
||||||
|
|
|
@ -2348,11 +2348,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
||||||
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
||||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
ty::Projection | ty::Inherent => {
|
||||||
format!("the associated type `{p}`")
|
format!("the associated type `{p}`")
|
||||||
}
|
}
|
||||||
ty::AliasKind::Weak => format!("the type alias `{p}`"),
|
ty::Weak => format!("the type alias `{p}`"),
|
||||||
ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
|
ty::Opaque => format!("the opaque type `{p}`"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
match a_ty.kind() {
|
match a_ty.kind() {
|
||||||
&ty::Alias(ty::AliasKind::Projection, data) => {
|
&ty::Alias(ty::Projection, data) => {
|
||||||
// FIXME: This does not handle subtyping correctly, we could
|
// FIXME: This does not handle subtyping correctly, we could
|
||||||
// instead create a new inference variable for `a_ty`, emitting
|
// instead create a new inference variable for `a_ty`, emitting
|
||||||
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
|
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
|
||||||
|
@ -522,10 +522,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// The old solver only accepts projection predicates for associated types.
|
// The old solver only accepts projection predicates for associated types.
|
||||||
ty::Alias(
|
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
|
||||||
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
|
return Err(TypeError::CyclicTy(a_ty));
|
||||||
_,
|
}
|
||||||
) => return Err(TypeError::CyclicTy(a_ty)),
|
|
||||||
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
|
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//! The functions in this file should fall back to the default set in their
|
//! The functions in this file should fall back to the default set in their
|
||||||
//! origin crate when the `TyCtxt` is not present in TLS.
|
//! origin crate when the `TyCtxt` is not present in TLS.
|
||||||
|
|
||||||
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
|
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTIC};
|
||||||
use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
|
use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
|
||||||
use rustc_middle::ty::tls;
|
use rustc_middle::ty::tls;
|
||||||
use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
|
use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
|
||||||
|
@ -103,5 +103,5 @@ pub fn setup_callbacks() {
|
||||||
.swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
.swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||||
rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
|
rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
|
||||||
.swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
.swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||||
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
|
TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::abi::{Abi, Size, WrappingRange};
|
use rustc_target::abi::{Abi, Size, WrappingRange};
|
||||||
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
||||||
use rustc_target::spec::abi::Abi as SpecAbi;
|
use rustc_target::spec::abi::Abi as SpecAbi;
|
||||||
use rustc_type_ir::DynKind;
|
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
|
||||||
}
|
}
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
|
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
|
||||||
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
|
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -787,7 +787,9 @@ LLVMRustOptimize(
|
||||||
for (auto PluginPath: Plugins) {
|
for (auto PluginPath: Plugins) {
|
||||||
auto Plugin = PassPlugin::Load(PluginPath.str());
|
auto Plugin = PassPlugin::Load(PluginPath.str());
|
||||||
if (!Plugin) {
|
if (!Plugin) {
|
||||||
LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
|
auto Err = Plugin.takeError();
|
||||||
|
auto ErrMsg = llvm::toString(std::move(Err));
|
||||||
|
LLVMRustSetLastError(ErrMsg.c_str());
|
||||||
return LLVMRustResult::Failure;
|
return LLVMRustResult::Failure;
|
||||||
}
|
}
|
||||||
Plugin->registerPassBuilderCallbacks(PB);
|
Plugin->registerPassBuilderCallbacks(PB);
|
||||||
|
|
|
@ -312,8 +312,9 @@ pub fn struct_lint_level(
|
||||||
// create a `DiagnosticBuilder` and continue as we would for warnings.
|
// create a `DiagnosticBuilder` and continue as we would for warnings.
|
||||||
rustc_errors::Level::Expect(expect_id)
|
rustc_errors::Level::Expect(expect_id)
|
||||||
}
|
}
|
||||||
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
|
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::ForceWarning(Some(expect_id)),
|
||||||
Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None),
|
Level::ForceWarn(None) => rustc_errors::Level::ForceWarning(None),
|
||||||
|
Level::Warn => rustc_errors::Level::Warning,
|
||||||
Level::Deny | Level::Forbid => rustc_errors::Level::Error,
|
Level::Deny | Level::Forbid => rustc_errors::Level::Error,
|
||||||
};
|
};
|
||||||
let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
|
let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
|
||||||
|
@ -350,22 +351,19 @@ pub fn struct_lint_level(
|
||||||
// suppressed the lint due to macros.
|
// suppressed the lint due to macros.
|
||||||
err.primary_message(msg);
|
err.primary_message(msg);
|
||||||
|
|
||||||
|
let name = lint.name_lower();
|
||||||
|
err.code(DiagnosticId::Lint { name, has_future_breakage });
|
||||||
|
|
||||||
// Lint diagnostics that are covered by the expect level will not be emitted outside
|
// Lint diagnostics that are covered by the expect level will not be emitted outside
|
||||||
// the compiler. It is therefore not necessary to add any information for the user.
|
// the compiler. It is therefore not necessary to add any information for the user.
|
||||||
// This will therefore directly call the decorate function which will in turn emit
|
// This will therefore directly call the decorate function which will in turn emit
|
||||||
// the `Diagnostic`.
|
// the `Diagnostic`.
|
||||||
if let Level::Expect(_) = level {
|
if let Level::Expect(_) = level {
|
||||||
let name = lint.name_lower();
|
|
||||||
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
|
|
||||||
decorate(&mut err);
|
decorate(&mut err);
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = lint.name_lower();
|
|
||||||
let is_force_warn = matches!(level, Level::ForceWarn(_));
|
|
||||||
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
|
|
||||||
|
|
||||||
if let Some(future_incompatible) = future_incompatible {
|
if let Some(future_incompatible) = future_incompatible {
|
||||||
let explanation = match future_incompatible.reason {
|
let explanation = match future_incompatible.reason {
|
||||||
FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
|
FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
|
||||||
|
|
|
@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||||
|
|
||||||
/// Whether this alias type is an opaque.
|
/// Whether this alias type is an opaque.
|
||||||
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
|
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||||
matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque))
|
matches!(self.opt_kind(tcx), Some(ty::Opaque))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
|
/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
|
||||||
|
@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
// Extern types have metadata = ().
|
// Extern types have metadata = ().
|
||||||
| ty::Foreign(..)
|
| ty::Foreign(..)
|
||||||
// `dyn*` has no metadata
|
// `dyn*` has no metadata
|
||||||
| ty::Dynamic(_, _, DynKind::DynStar)
|
| ty::Dynamic(_, _, ty::DynStar)
|
||||||
// If returned by `struct_tail_without_normalization` this is a unit struct
|
// If returned by `struct_tail_without_normalization` this is a unit struct
|
||||||
// without any fields, or not a struct, and therefore is Sized.
|
// without any fields, or not a struct, and therefore is Sized.
|
||||||
| ty::Adt(..)
|
| ty::Adt(..)
|
||||||
|
@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
| ty::Tuple(..) => (tcx.types.unit, false),
|
| ty::Tuple(..) => (tcx.types.unit, false),
|
||||||
|
|
||||||
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
|
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
|
||||||
ty::Dynamic(_, _, DynKind::Dyn) => {
|
ty::Dynamic(_, _, ty::Dyn) => {
|
||||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
||||||
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
|
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
|
||||||
},
|
},
|
||||||
|
|
|
@ -432,7 +432,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrut_ty = scrut.ty;
|
let scrut_ty = scrut.ty;
|
||||||
let report = analyze_match(&cx, &tarms, scrut_ty);
|
let report = match analyze_match(&cx, &tarms, scrut_ty) {
|
||||||
|
Ok(report) => report,
|
||||||
|
Err(err) => {
|
||||||
|
self.error = Err(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match source {
|
match source {
|
||||||
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
|
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
|
||||||
|
@ -546,7 +552,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||||
let cx = self.new_cx(refutability, None, scrut, pat.span);
|
let cx = self.new_cx(refutability, None, scrut, pat.span);
|
||||||
let pat = self.lower_pattern(&cx, pat)?;
|
let pat = self.lower_pattern(&cx, pat)?;
|
||||||
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
|
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
|
||||||
let report = analyze_match(&cx, &arms, pat.ty().inner());
|
let report = analyze_match(&cx, &arms, pat.ty().inner())?;
|
||||||
Ok((cx, report))
|
Ok((cx, report))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ use std::fmt;
|
||||||
use rustc_index::Idx;
|
use rustc_index::Idx;
|
||||||
#[cfg(feature = "rustc")]
|
#[cfg(feature = "rustc")]
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
|
#[cfg(feature = "rustc")]
|
||||||
|
use rustc_span::ErrorGuaranteed;
|
||||||
|
|
||||||
use crate::constructor::{Constructor, ConstructorSet};
|
use crate::constructor::{Constructor, ConstructorSet};
|
||||||
#[cfg(feature = "rustc")]
|
#[cfg(feature = "rustc")]
|
||||||
|
@ -52,6 +54,8 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
|
||||||
pub trait TypeCx: Sized + fmt::Debug {
|
pub trait TypeCx: Sized + fmt::Debug {
|
||||||
/// The type of a pattern.
|
/// The type of a pattern.
|
||||||
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
|
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
|
||||||
|
/// Errors that can abort analysis.
|
||||||
|
type Error: fmt::Debug;
|
||||||
/// The index of an enum variant.
|
/// The index of an enum variant.
|
||||||
type VariantIdx: Clone + Idx;
|
type VariantIdx: Clone + Idx;
|
||||||
/// A string literal
|
/// A string literal
|
||||||
|
@ -73,7 +77,7 @@ pub trait TypeCx: Sized + fmt::Debug {
|
||||||
/// The set of all the constructors for `ty`.
|
/// The set of all the constructors for `ty`.
|
||||||
///
|
///
|
||||||
/// This must follow the invariants of `ConstructorSet`
|
/// This must follow the invariants of `ConstructorSet`
|
||||||
fn ctors_for_ty(&self, ty: Self::Ty) -> ConstructorSet<Self>;
|
fn ctors_for_ty(&self, ty: Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
|
||||||
|
|
||||||
/// Best-effort `Debug` implementation.
|
/// Best-effort `Debug` implementation.
|
||||||
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
|
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
|
||||||
|
@ -109,25 +113,25 @@ pub fn analyze_match<'p, 'tcx>(
|
||||||
tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
|
tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
|
||||||
arms: &[rustc::MatchArm<'p, 'tcx>],
|
arms: &[rustc::MatchArm<'p, 'tcx>],
|
||||||
scrut_ty: Ty<'tcx>,
|
scrut_ty: Ty<'tcx>,
|
||||||
) -> rustc::UsefulnessReport<'p, 'tcx> {
|
) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
|
||||||
// Arena to store the extra wildcards we construct during analysis.
|
// Arena to store the extra wildcards we construct during analysis.
|
||||||
let wildcard_arena = tycx.pattern_arena;
|
let wildcard_arena = tycx.pattern_arena;
|
||||||
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
|
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
|
||||||
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
|
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
|
||||||
let cx = MatchCtxt { tycx, wildcard_arena };
|
let cx = MatchCtxt { tycx, wildcard_arena };
|
||||||
|
|
||||||
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
|
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?;
|
||||||
|
|
||||||
let pat_column = PatternColumn::new(arms);
|
let pat_column = PatternColumn::new(arms);
|
||||||
|
|
||||||
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
|
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
|
||||||
lint_overlapping_range_endpoints(cx, &pat_column);
|
lint_overlapping_range_endpoints(cx, &pat_column)?;
|
||||||
|
|
||||||
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
|
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
|
||||||
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
|
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
|
||||||
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
|
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
|
||||||
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
|
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
report
|
Ok(report)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc_data_structures::captures::Captures;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||||
use rustc_span::Span;
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
|
|
||||||
use crate::constructor::{IntRange, MaybeInfiniteInt};
|
use crate::constructor::{IntRange, MaybeInfiniteInt};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
|
@ -59,9 +59,13 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do constructor splitting on the constructors of the column.
|
/// Do constructor splitting on the constructors of the column.
|
||||||
fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> {
|
fn analyze_ctors(
|
||||||
|
&self,
|
||||||
|
pcx: &PlaceCtxt<'_, 'p, 'tcx>,
|
||||||
|
) -> Result<SplitConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
|
||||||
let column_ctors = self.patterns.iter().map(|p| p.ctor());
|
let column_ctors = self.patterns.iter().map(|p| p.ctor());
|
||||||
pcx.ctors_for_ty().split(pcx, column_ctors)
|
let ctors_for_ty = &pcx.ctors_for_ty()?;
|
||||||
|
Ok(ctors_for_ty.split(pcx, column_ctors))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'_> {
|
fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'_> {
|
||||||
|
@ -106,18 +110,18 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
||||||
fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
cx: MatchCtxt<'a, 'p, 'tcx>,
|
cx: MatchCtxt<'a, 'p, 'tcx>,
|
||||||
column: &PatternColumn<'p, 'tcx>,
|
column: &PatternColumn<'p, 'tcx>,
|
||||||
) -> Vec<WitnessPat<'p, 'tcx>> {
|
) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> {
|
||||||
let Some(ty) = column.head_ty() else {
|
let Some(ty) = column.head_ty() else {
|
||||||
return Vec::new();
|
return Ok(Vec::new());
|
||||||
};
|
};
|
||||||
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
||||||
|
|
||||||
let set = column.analyze_ctors(pcx);
|
let set = column.analyze_ctors(pcx)?;
|
||||||
if set.present.is_empty() {
|
if set.present.is_empty() {
|
||||||
// We can't consistently handle the case where no constructors are present (since this would
|
// We can't consistently handle the case where no constructors are present (since this would
|
||||||
// require digging deep through any type in case there's a non_exhaustive enum somewhere),
|
// require digging deep through any type in case there's a non_exhaustive enum somewhere),
|
||||||
// so for consistency we refuse to handle the top-level case, where we could handle it.
|
// so for consistency we refuse to handle the top-level case, where we could handle it.
|
||||||
return vec![];
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut witnesses = Vec::new();
|
let mut witnesses = Vec::new();
|
||||||
|
@ -137,7 +141,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
|
let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
|
||||||
for (i, col_i) in specialized_columns.iter().enumerate() {
|
for (i, col_i) in specialized_columns.iter().enumerate() {
|
||||||
// Compute witnesses for each column.
|
// Compute witnesses for each column.
|
||||||
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i);
|
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i)?;
|
||||||
// For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
|
// For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
|
||||||
// adding enough wildcards to match `arity`.
|
// adding enough wildcards to match `arity`.
|
||||||
for wit in wits_for_col_i {
|
for wit in wits_for_col_i {
|
||||||
|
@ -147,7 +151,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
witnesses
|
Ok(witnesses)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
|
@ -155,13 +159,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
arms: &[MatchArm<'p, 'tcx>],
|
arms: &[MatchArm<'p, 'tcx>],
|
||||||
pat_column: &PatternColumn<'p, 'tcx>,
|
pat_column: &PatternColumn<'p, 'tcx>,
|
||||||
scrut_ty: RevealedTy<'tcx>,
|
scrut_ty: RevealedTy<'tcx>,
|
||||||
) {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
|
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
|
||||||
if !matches!(
|
if !matches!(
|
||||||
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
|
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
|
||||||
rustc_session::lint::Level::Allow
|
rustc_session::lint::Level::Allow
|
||||||
) {
|
) {
|
||||||
let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column);
|
let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column)?;
|
||||||
if !witnesses.is_empty() {
|
if !witnesses.is_empty() {
|
||||||
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
||||||
// is not exhaustive enough.
|
// is not exhaustive enough.
|
||||||
|
@ -200,6 +204,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
|
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
|
||||||
|
@ -207,14 +212,14 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||||
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
|
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
|
||||||
cx: MatchCtxt<'a, 'p, 'tcx>,
|
cx: MatchCtxt<'a, 'p, 'tcx>,
|
||||||
column: &PatternColumn<'p, 'tcx>,
|
column: &PatternColumn<'p, 'tcx>,
|
||||||
) {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let Some(ty) = column.head_ty() else {
|
let Some(ty) = column.head_ty() else {
|
||||||
return;
|
return Ok(());
|
||||||
};
|
};
|
||||||
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
||||||
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
|
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
|
||||||
|
|
||||||
let set = column.analyze_ctors(pcx);
|
let set = column.analyze_ctors(pcx)?;
|
||||||
|
|
||||||
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
|
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
|
||||||
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
|
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
|
||||||
|
@ -271,8 +276,9 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
|
||||||
// Recurse into the fields.
|
// Recurse into the fields.
|
||||||
for ctor in set.present {
|
for ctor in set.present {
|
||||||
for col in column.specialize(pcx, &ctor) {
|
for col in column.specialize(pcx, &ctor) {
|
||||||
lint_overlapping_range_endpoints(cx, &col);
|
lint_overlapping_range_endpoints(cx, &col)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,9 @@ use rustc_middle::mir::interpret::Scalar;
|
||||||
use rustc_middle::mir::{self, Const};
|
use rustc_middle::mir::{self, Const};
|
||||||
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
|
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
|
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
|
||||||
|
use rustc_span::ErrorGuaranteed;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -302,7 +304,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
///
|
///
|
||||||
/// See [`crate::constructor`] for considerations of emptiness.
|
/// See [`crate::constructor`] for considerations of emptiness.
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
pub fn ctors_for_ty(&self, ty: RevealedTy<'tcx>) -> ConstructorSet<'p, 'tcx> {
|
pub fn ctors_for_ty(
|
||||||
|
&self,
|
||||||
|
ty: RevealedTy<'tcx>,
|
||||||
|
) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
|
||||||
let cx = self;
|
let cx = self;
|
||||||
let make_uint_range = |start, end| {
|
let make_uint_range = |start, end| {
|
||||||
IntRange::from_range(
|
IntRange::from_range(
|
||||||
|
@ -311,9 +316,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
RangeEnd::Included,
|
RangeEnd::Included,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
// Abort on type error.
|
||||||
|
ty.error_reported()?;
|
||||||
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
||||||
// arrays and slices we use ranges and variable-length slices when appropriate.
|
// arrays and slices we use ranges and variable-length slices when appropriate.
|
||||||
match ty.kind() {
|
Ok(match ty.kind() {
|
||||||
ty::Bool => ConstructorSet::Bool,
|
ty::Bool => ConstructorSet::Bool,
|
||||||
ty::Char => {
|
ty::Char => {
|
||||||
// The valid Unicode Scalar Value ranges.
|
// The valid Unicode Scalar Value ranges.
|
||||||
|
@ -423,7 +430,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
|
ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||||
bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
|
bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_pat_range_bdy(
|
pub(crate) fn lower_pat_range_bdy(
|
||||||
|
@ -944,6 +951,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
|
|
||||||
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
type Ty = RevealedTy<'tcx>;
|
type Ty = RevealedTy<'tcx>;
|
||||||
|
type Error = ErrorGuaranteed;
|
||||||
type VariantIdx = VariantIdx;
|
type VariantIdx = VariantIdx;
|
||||||
type StrLit = Const<'tcx>;
|
type StrLit = Const<'tcx>;
|
||||||
type ArmData = HirId;
|
type ArmData = HirId;
|
||||||
|
@ -963,7 +971,10 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
) -> &[Self::Ty] {
|
) -> &[Self::Ty] {
|
||||||
self.ctor_sub_tys(ctor, ty)
|
self.ctor_sub_tys(ctor, ty)
|
||||||
}
|
}
|
||||||
fn ctors_for_ty(&self, ty: Self::Ty) -> crate::constructor::ConstructorSet<Self> {
|
fn ctors_for_ty(
|
||||||
|
&self,
|
||||||
|
ty: Self::Ty,
|
||||||
|
) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
|
||||||
self.ctors_for_ty(ty)
|
self.ctors_for_ty(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -753,7 +753,7 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> {
|
||||||
pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
|
pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
|
||||||
self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
|
self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
|
||||||
}
|
}
|
||||||
pub(crate) fn ctors_for_ty(&self) -> ConstructorSet<Cx> {
|
pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
|
||||||
self.mcx.tycx.ctors_for_ty(self.ty)
|
self.mcx.tycx.ctors_for_ty(self.ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1336,14 +1336,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
mcx: MatchCtxt<'a, 'p, Cx>,
|
mcx: MatchCtxt<'a, 'p, Cx>,
|
||||||
matrix: &mut Matrix<'p, Cx>,
|
matrix: &mut Matrix<'p, Cx>,
|
||||||
is_top_level: bool,
|
is_top_level: bool,
|
||||||
) -> WitnessMatrix<Cx> {
|
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
|
||||||
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
||||||
|
|
||||||
if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) {
|
if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) {
|
||||||
// Here we know that nothing will contribute further to exhaustiveness or usefulness. This
|
// Here we know that nothing will contribute further to exhaustiveness or usefulness. This
|
||||||
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
|
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
|
||||||
// the file for details.
|
// the file for details.
|
||||||
return WitnessMatrix::empty();
|
return Ok(WitnessMatrix::empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(ty) = matrix.head_ty() else {
|
let Some(ty) = matrix.head_ty() else {
|
||||||
|
@ -1355,16 +1355,16 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
// When there's an unguarded row, the match is exhaustive and any subsequent row is not
|
// When there's an unguarded row, the match is exhaustive and any subsequent row is not
|
||||||
// useful.
|
// useful.
|
||||||
if !row.is_under_guard {
|
if !row.is_under_guard {
|
||||||
return WitnessMatrix::empty();
|
return Ok(WitnessMatrix::empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
|
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
|
||||||
// irrelevant.
|
// irrelevant.
|
||||||
return if matrix.wildcard_row_is_relevant {
|
return if matrix.wildcard_row_is_relevant {
|
||||||
WitnessMatrix::unit_witness()
|
Ok(WitnessMatrix::unit_witness())
|
||||||
} else {
|
} else {
|
||||||
// We choose to not report anything here; see at the top for details.
|
// We choose to not report anything here; see at the top for details.
|
||||||
WitnessMatrix::empty()
|
Ok(WitnessMatrix::empty())
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1378,7 +1378,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
|
|
||||||
// Analyze the constructors present in this column.
|
// Analyze the constructors present in this column.
|
||||||
let ctors = matrix.heads().map(|p| p.ctor());
|
let ctors = matrix.heads().map(|p| p.ctor());
|
||||||
let ctors_for_ty = pcx.ctors_for_ty();
|
let ctors_for_ty = pcx.ctors_for_ty()?;
|
||||||
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
|
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
|
||||||
let split_set = ctors_for_ty.split(pcx, ctors);
|
let split_set = ctors_for_ty.split(pcx, ctors);
|
||||||
let all_missing = split_set.present.is_empty();
|
let all_missing = split_set.present.is_empty();
|
||||||
|
@ -1417,7 +1417,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
|
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
|
||||||
let mut witnesses = ensure_sufficient_stack(|| {
|
let mut witnesses = ensure_sufficient_stack(|| {
|
||||||
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
|
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
|
||||||
});
|
})?;
|
||||||
|
|
||||||
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
|
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
|
||||||
witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors);
|
witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors);
|
||||||
|
@ -1438,7 +1438,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates whether or not a given arm is useful.
|
/// Indicates whether or not a given arm is useful.
|
||||||
|
@ -1469,9 +1469,10 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||||
arms: &[MatchArm<'p, Cx>],
|
arms: &[MatchArm<'p, Cx>],
|
||||||
scrut_ty: Cx::Ty,
|
scrut_ty: Cx::Ty,
|
||||||
scrut_validity: ValidityConstraint,
|
scrut_validity: ValidityConstraint,
|
||||||
) -> UsefulnessReport<'p, Cx> {
|
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
|
||||||
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
|
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
|
||||||
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true);
|
let non_exhaustiveness_witnesses =
|
||||||
|
compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
|
||||||
|
|
||||||
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
|
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
|
||||||
let arm_usefulness: Vec<_> = arms
|
let arm_usefulness: Vec<_> = arms
|
||||||
|
@ -1488,5 +1489,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||||
(arm, usefulness)
|
(arm, usefulness)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
|
Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
// separate step to be able to collapse the adjacent spans that rustfix
|
// separate step to be able to collapse the adjacent spans that rustfix
|
||||||
// will remove
|
// will remove
|
||||||
//
|
//
|
||||||
// - `check_crate` finally emits the diagnostics based on the data generated
|
// - `check_unused` finally emits the diagnostics based on the data generated
|
||||||
// in the last step
|
// in the last step
|
||||||
|
|
||||||
use crate::imports::ImportKind;
|
use crate::imports::ImportKind;
|
||||||
|
|
|
@ -143,11 +143,7 @@ pub fn feature_warn_issue(
|
||||||
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
|
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
|
||||||
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
|
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
|
||||||
let future_incompatible = lint.future_incompatible.as_ref().unwrap();
|
let future_incompatible = lint.future_incompatible.as_ref().unwrap();
|
||||||
err.code(DiagnosticId::Lint {
|
err.code(DiagnosticId::Lint { name: lint.name_lower(), has_future_breakage: false });
|
||||||
name: lint.name_lower(),
|
|
||||||
has_future_breakage: false,
|
|
||||||
is_force_warn: false,
|
|
||||||
});
|
|
||||||
err.warn(lint.desc);
|
err.warn(lint.desc);
|
||||||
err.note(format!("for more information, see {}", future_incompatible.reference));
|
err.note(format!("for more information, see {}", future_incompatible.reference));
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use stable_mir::ty::{
|
||||||
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
|
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
|
||||||
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
|
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
|
||||||
};
|
};
|
||||||
use stable_mir::{CrateItem, DefId};
|
use stable_mir::{CrateItem, CrateNum, DefId};
|
||||||
|
|
||||||
use super::RustcInternal;
|
use super::RustcInternal;
|
||||||
|
|
||||||
|
@ -28,6 +28,13 @@ impl<'tcx> RustcInternal<'tcx> for CrateItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for CrateNum {
|
||||||
|
type T = rustc_span::def_id::CrateNum;
|
||||||
|
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
rustc_span::def_id::CrateNum::from_usize(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> RustcInternal<'tcx> for DefId {
|
impl<'tcx> RustcInternal<'tcx> for DefId {
|
||||||
type T = rustc_span::def_id::DefId;
|
type T = rustc_span::def_id::DefId;
|
||||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
|
|
@ -25,8 +25,9 @@ use stable_mir::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
||||||
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
|
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
|
||||||
};
|
};
|
||||||
use stable_mir::{Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
|
use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use crate::rustc_internal::{internal, RustcInternal};
|
use crate::rustc_internal::{internal, RustcInternal};
|
||||||
use crate::rustc_smir::builder::BodyBuilder;
|
use crate::rustc_smir::builder::BodyBuilder;
|
||||||
|
@ -67,10 +68,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
|
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
tables
|
tables
|
||||||
.tcx
|
.tcx
|
||||||
.traits(LOCAL_CRATE)
|
.traits(crate_num.internal(&mut *tables))
|
||||||
.iter()
|
.iter()
|
||||||
.map(|trait_def_id| tables.trait_def(*trait_def_id))
|
.map(|trait_def_id| tables.trait_def(*trait_def_id))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -84,10 +90,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
|
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
iter::once(LOCAL_CRATE)
|
||||||
|
.chain(tables.tcx.crates(()).iter().copied())
|
||||||
|
.flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter())
|
||||||
|
.map(|impl_def_id| tables.impl_def(*impl_def_id))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
tables
|
tables
|
||||||
.tcx
|
.tcx
|
||||||
.trait_impls_in_crate(LOCAL_CRATE)
|
.trait_impls_in_crate(crate_num.internal(&mut *tables))
|
||||||
.iter()
|
.iter()
|
||||||
.map(|impl_def_id| tables.impl_def(*impl_def_id))
|
.map(|impl_def_id| tables.impl_def(*impl_def_id))
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
|
||||||
impl<'tcx> Stable<'tcx> for ty::AliasKind {
|
impl<'tcx> Stable<'tcx> for ty::AliasKind {
|
||||||
type T = stable_mir::ty::AliasKind;
|
type T = stable_mir::ty::AliasKind;
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
use rustc_middle::ty::AliasKind::*;
|
|
||||||
match self {
|
match self {
|
||||||
Projection => stable_mir::ty::AliasKind::Projection,
|
ty::Projection => stable_mir::ty::AliasKind::Projection,
|
||||||
Inherent => stable_mir::ty::AliasKind::Inherent,
|
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
|
||||||
Opaque => stable_mir::ty::AliasKind::Opaque,
|
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
|
||||||
Weak => stable_mir::ty::AliasKind::Weak,
|
ty::Weak => stable_mir::ty::AliasKind::Weak,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
|
||||||
type T = stable_mir::ty::DynKind;
|
type T = stable_mir::ty::DynKind;
|
||||||
|
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
use rustc_middle::ty::DynKind;
|
|
||||||
match self {
|
match self {
|
||||||
DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
|
ty::Dyn => stable_mir::ty::DynKind::Dyn,
|
||||||
DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
|
ty::DynStar => stable_mir::ty::DynKind::DynStar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,29 @@
|
||||||
//! Doing this via a separate goal is called "deferred alias relation" and part
|
//! Doing this via a separate goal is called "deferred alias relation" and part
|
||||||
//! of our more general approach to "lazy normalization".
|
//! of our more general approach to "lazy normalization".
|
||||||
//!
|
//!
|
||||||
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
|
//! This is done by first normalizing both sides of the goal, ending up in
|
||||||
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
|
//! either a concrete type, rigid projection, opaque, or an infer variable.
|
||||||
//! projection predicate with B as the right-hand side of the projection.
|
//! These are related further according to the rules below:
|
||||||
//! This goal is computed in both directions, if both are aliases.
|
//!
|
||||||
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
|
//! (1.) If we end up with a rigid projection and a rigid projection, then we
|
||||||
//! aliases with the same def-id.
|
//! relate those projections structurally.
|
||||||
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
|
//!
|
||||||
//! may apply, then we can compute the "intersection" of both normalizes-to by
|
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
|
||||||
//! performing them together. This is used specifically to resolve ambiguities.
|
//! have its hidden type defined to be that rigid projection.
|
||||||
|
//!
|
||||||
|
//! (3.) If we end up with an opaque and an opaque, then we assemble two
|
||||||
|
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
|
||||||
|
//! versa.
|
||||||
|
//!
|
||||||
|
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
|
||||||
|
//! we assign the alias to the infer var.
|
||||||
|
//!
|
||||||
|
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
|
||||||
|
//! define the hidden type of the opaque to be the rigid type.
|
||||||
|
//!
|
||||||
|
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
|
||||||
|
//! relate them structurally.
|
||||||
|
|
||||||
use super::{EvalCtxt, GoalSource};
|
use super::{EvalCtxt, GoalSource};
|
||||||
use rustc_infer::infer::DefineOpaqueTypes;
|
use rustc_infer::infer::DefineOpaqueTypes;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
} else if alias.is_opaque(tcx) {
|
||||||
|
// FIXME: This doesn't account for variance.
|
||||||
self.define_opaque(param_env, alias, rhs)
|
self.define_opaque(param_env, alias, rhs)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
|
@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
} else if alias.is_opaque(tcx) {
|
||||||
|
// FIXME: This doesn't account for variance.
|
||||||
self.define_opaque(param_env, alias, lhs)
|
self.define_opaque(param_env, alias, lhs)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
|
@ -72,6 +88,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
|
||||||
/// Normalize the `term` to equate it later. This does not define opaque types.
|
/// Normalize the `term` to equate it later. This does not define opaque types.
|
||||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||||
fn try_normalize_term(
|
fn try_normalize_term(
|
||||||
|
|
|
@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
|
||||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||||
QueryResult, Response,
|
QueryResult, Response,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::traits::Reveal;
|
||||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||||
|
@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
return Some(ty);
|
return Some(ty);
|
||||||
};
|
};
|
||||||
|
|
||||||
// We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
|
// We do no always define opaque types eagerly to allow non-defining uses
|
||||||
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
|
// in the defining scope. However, if we can unify this opaque to an existing
|
||||||
if let Some(def_id) = alias.def_id.as_local() {
|
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
|
||||||
if self
|
// through.
|
||||||
.unify_existing_opaque_tys(
|
if let DefineOpaqueTypes::No = define_opaque_types
|
||||||
param_env,
|
&& let Reveal::UserFacing = param_env.reveal()
|
||||||
OpaqueTypeKey { def_id, args: alias.args },
|
&& let ty::Opaque = kind
|
||||||
self.next_ty_infer(),
|
&& let Some(def_id) = alias.def_id.as_local()
|
||||||
)
|
&& self.can_define_opaque_ty(def_id)
|
||||||
.is_empty()
|
{
|
||||||
{
|
if self
|
||||||
return Some(ty);
|
.unify_existing_opaque_tys(
|
||||||
}
|
param_env,
|
||||||
|
OpaqueTypeKey { def_id, args: alias.args },
|
||||||
|
self.next_ty_infer(),
|
||||||
|
)
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
return Some(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ use crate::ty::{
|
||||||
TraitDef, Ty, TyKind, VariantDef,
|
TraitDef, Ty, TyKind, VariantDef,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
|
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
|
||||||
TraitDecls,
|
Symbol, TraitDecls,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This trait defines the interface between stable_mir and the Rust compiler.
|
/// This trait defines the interface between stable_mir and the Rust compiler.
|
||||||
|
@ -32,8 +32,10 @@ pub trait Context {
|
||||||
/// Check whether the body of a function is available.
|
/// Check whether the body of a function is available.
|
||||||
fn has_body(&self, item: DefId) -> bool;
|
fn has_body(&self, item: DefId) -> bool;
|
||||||
fn all_trait_decls(&self) -> TraitDecls;
|
fn all_trait_decls(&self) -> TraitDecls;
|
||||||
|
fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
|
||||||
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
|
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
|
||||||
fn all_trait_impls(&self) -> ImplTraitDecls;
|
fn all_trait_impls(&self) -> ImplTraitDecls;
|
||||||
|
fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
|
||||||
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
|
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
|
||||||
fn generics_of(&self, def_id: DefId) -> Generics;
|
fn generics_of(&self, def_id: DefId) -> Generics;
|
||||||
fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
|
fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub use crate::error::*;
|
||||||
use crate::mir::pretty::function_name;
|
use crate::mir::pretty::function_name;
|
||||||
use crate::mir::Body;
|
use crate::mir::Body;
|
||||||
use crate::mir::Mutability;
|
use crate::mir::Mutability;
|
||||||
use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
|
use crate::ty::{ImplDef, IndexedVal, Span, TraitDef, Ty};
|
||||||
|
|
||||||
pub mod abi;
|
pub mod abi;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -86,6 +86,18 @@ pub struct Crate {
|
||||||
pub is_local: bool,
|
pub is_local: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Crate {
|
||||||
|
/// The list of traits declared in this crate.
|
||||||
|
pub fn trait_decls(&self) -> TraitDecls {
|
||||||
|
with(|cx| cx.trait_decls(self.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of trait implementations in this crate.
|
||||||
|
pub fn trait_impls(&self) -> ImplTraitDecls {
|
||||||
|
with(|cx| cx.trait_impls(self.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub enum ItemKind {
|
pub enum ItemKind {
|
||||||
Fn,
|
Fn,
|
||||||
|
@ -169,18 +181,10 @@ pub fn all_trait_decls() -> TraitDecls {
|
||||||
with(|cx| cx.all_trait_decls())
|
with(|cx| cx.all_trait_decls())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_decl(trait_def: &TraitDef) -> TraitDecl {
|
|
||||||
with(|cx| cx.trait_decl(trait_def))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all_trait_impls() -> ImplTraitDecls {
|
pub fn all_trait_impls() -> ImplTraitDecls {
|
||||||
with(|cx| cx.all_trait_impls())
|
with(|cx| cx.all_trait_impls())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
|
|
||||||
with(|cx| cx.trait_impl(trait_impl))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type that provides internal information but that can still be used for debug purpose.
|
/// A type that provides internal information but that can still be used for debug purpose.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Opaque(String);
|
pub struct Opaque(String);
|
||||||
|
|
|
@ -714,9 +714,16 @@ crate_def! {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate_def! {
|
crate_def! {
|
||||||
|
/// A trait's definition.
|
||||||
pub TraitDef;
|
pub TraitDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TraitDef {
|
||||||
|
pub fn declaration(trait_def: &TraitDef) -> TraitDecl {
|
||||||
|
with(|cx| cx.trait_decl(trait_def))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate_def! {
|
crate_def! {
|
||||||
pub GenericDef;
|
pub GenericDef;
|
||||||
}
|
}
|
||||||
|
@ -726,9 +733,17 @@ crate_def! {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate_def! {
|
crate_def! {
|
||||||
|
/// A trait impl definition.
|
||||||
pub ImplDef;
|
pub ImplDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImplDef {
|
||||||
|
/// Retrieve information about this implementation.
|
||||||
|
pub fn trait_impl(&self) -> ImplTrait {
|
||||||
|
with(|cx| cx.trait_impl(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate_def! {
|
crate_def! {
|
||||||
pub RegionDef;
|
pub RegionDef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -771,7 +771,11 @@ impl Ipv4Addr {
|
||||||
|| self.is_loopback()
|
|| self.is_loopback()
|
||||||
|| self.is_link_local()
|
|| self.is_link_local()
|
||||||
// addresses reserved for future protocols (`192.0.0.0/24`)
|
// addresses reserved for future protocols (`192.0.0.0/24`)
|
||||||
||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
|
// .9 and .10 are documented as globally reachable so they're excluded
|
||||||
|
|| (
|
||||||
|
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
|
||||||
|
&& self.octets()[3] != 9 && self.octets()[3] != 10
|
||||||
|
)
|
||||||
|| self.is_documentation()
|
|| self.is_documentation()
|
||||||
|| self.is_benchmarking()
|
|| self.is_benchmarking()
|
||||||
|| self.is_reserved()
|
|| self.is_reserved()
|
||||||
|
@ -1515,8 +1519,12 @@ impl Ipv6Addr {
|
||||||
// AS112-v6 (`2001:4:112::/48`)
|
// AS112-v6 (`2001:4:112::/48`)
|
||||||
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
||||||
// ORCHIDv2 (`2001:20::/28`)
|
// ORCHIDv2 (`2001:20::/28`)
|
||||||
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
|
// Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)`
|
||||||
|
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
|
||||||
))
|
))
|
||||||
|
// 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable,
|
||||||
|
// IANA says N/A.
|
||||||
|
|| matches!(self.segments(), [0x2002, _, _, _, _, _, _, _])
|
||||||
|| self.is_documentation()
|
|| self.is_documentation()
|
||||||
|| self.is_unique_local()
|
|| self.is_unique_local()
|
||||||
|| self.is_unicast_link_local())
|
|| self.is_unicast_link_local())
|
||||||
|
|
|
@ -461,6 +461,10 @@ fn ipv4_properties() {
|
||||||
check!("198.18.54.2", benchmarking);
|
check!("198.18.54.2", benchmarking);
|
||||||
check!("198.19.255.255", benchmarking);
|
check!("198.19.255.255", benchmarking);
|
||||||
check!("192.0.0.0");
|
check!("192.0.0.0");
|
||||||
|
check!("192.0.0.8");
|
||||||
|
check!("192.0.0.9", global);
|
||||||
|
check!("192.0.0.10", global);
|
||||||
|
check!("192.0.0.11");
|
||||||
check!("192.0.0.255");
|
check!("192.0.0.255");
|
||||||
check!("192.0.0.100");
|
check!("192.0.0.100");
|
||||||
check!("240.0.0.0", reserved);
|
check!("240.0.0.0", reserved);
|
||||||
|
@ -480,6 +484,10 @@ fn ipv6_properties() {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
|
($s:expr, &[$($octet:expr),*]) => {
|
||||||
|
check!($s, &[$($octet),*], 0);
|
||||||
|
};
|
||||||
|
|
||||||
($s:expr, &[$($octet:expr),*], $mask:expr) => {
|
($s:expr, &[$($octet:expr),*], $mask:expr) => {
|
||||||
assert_eq!($s, ip!($s).to_string());
|
assert_eq!($s, ip!($s).to_string());
|
||||||
let octets = &[$($octet),*];
|
let octets = &[$($octet),*];
|
||||||
|
@ -656,8 +664,8 @@ fn ipv6_properties() {
|
||||||
&[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
&[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
global | unicast_global
|
global | unicast_global
|
||||||
);
|
);
|
||||||
|
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
|
||||||
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
|
check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
|
||||||
|
|
||||||
check!(
|
check!(
|
||||||
"2001:200::",
|
"2001:200::",
|
||||||
|
@ -665,6 +673,8 @@ fn ipv6_properties() {
|
||||||
global | unicast_global
|
global | unicast_global
|
||||||
);
|
);
|
||||||
|
|
||||||
|
check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
|
||||||
|
|
||||||
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
|
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
|
||||||
|
|
||||||
check!(
|
check!(
|
||||||
|
|
|
@ -383,8 +383,6 @@ impl<T: ?Sized> Mutex<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(mutex_unpoison)]
|
|
||||||
///
|
|
||||||
/// use std::sync::{Arc, Mutex};
|
/// use std::sync::{Arc, Mutex};
|
||||||
/// use std::thread;
|
/// use std::thread;
|
||||||
///
|
///
|
||||||
|
@ -406,7 +404,7 @@ impl<T: ?Sized> Mutex<T> {
|
||||||
/// assert_eq!(*x, 1);
|
/// assert_eq!(*x, 1);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "mutex_unpoison", issue = "96469")]
|
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub fn clear_poison(&self) {
|
pub fn clear_poison(&self) {
|
||||||
self.poison.clear();
|
self.poison.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,8 +387,6 @@ impl<T: ?Sized> RwLock<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(mutex_unpoison)]
|
|
||||||
///
|
|
||||||
/// use std::sync::{Arc, RwLock};
|
/// use std::sync::{Arc, RwLock};
|
||||||
/// use std::thread;
|
/// use std::thread;
|
||||||
///
|
///
|
||||||
|
@ -410,7 +408,7 @@ impl<T: ?Sized> RwLock<T> {
|
||||||
/// assert_eq!(*guard, 1);
|
/// assert_eq!(*guard, 1);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "mutex_unpoison", issue = "96469")]
|
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub fn clear_poison(&self) {
|
pub fn clear_poison(&self) {
|
||||||
self.poison.clear();
|
self.poison.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,90 @@ fn bar() {}
|
||||||
fn baz() {}
|
fn baz() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Sorting
|
||||||
|
|
||||||
|
In various cases, the default Rust style specifies to sort things. If not
|
||||||
|
otherwise specified, such sorting should be "version sorting", which ensures
|
||||||
|
that (for instance) `x8` comes before `x16` even though the character `1` comes
|
||||||
|
before the character `8`. (If not otherwise specified, version-sorting is
|
||||||
|
lexicographical.)
|
||||||
|
|
||||||
|
For the purposes of the Rust style, to compare two strings for version-sorting:
|
||||||
|
|
||||||
|
- Process both strings from beginning to end as two sequences of maximal-length
|
||||||
|
chunks, where each chunk consists either of a sequence of characters other
|
||||||
|
than ASCII digits, or a sequence of ASCII digits (a numeric chunk), and
|
||||||
|
compare corresponding chunks from the strings.
|
||||||
|
- To compare two numeric chunks, compare them by numeric value, ignoring
|
||||||
|
leading zeroes. If the two chunks have equal numeric value, but different
|
||||||
|
numbers of leading digits, and this is the first time this has happened for
|
||||||
|
these strings, treat the chunks as equal (moving on to the next chunk) but
|
||||||
|
remember which string had more leading zeroes.
|
||||||
|
- To compare two chunks if both are not numeric, compare them by Unicode
|
||||||
|
character lexicographically, except that `_` (underscore) sorts immediately
|
||||||
|
after ` ` (space) but before any other character. (This treats underscore as
|
||||||
|
a word separator, as commonly used in identifiers.)
|
||||||
|
- If the use of version sorting specifies further modifiers, such as sorting
|
||||||
|
non-lowercase before lowercase, apply those modifiers to the lexicographic
|
||||||
|
sort in this step.
|
||||||
|
- If the comparison reaches the end of the string and considers each pair of
|
||||||
|
chunks equal:
|
||||||
|
- If one of the numeric comparisons noted the earliest point at which one
|
||||||
|
string had more leading zeroes than the other, sort the string with more
|
||||||
|
leading zeroes first.
|
||||||
|
- Otherwise, the strings are equal.
|
||||||
|
|
||||||
|
Note that there exist various algorithms called "version sorting", which
|
||||||
|
generally try to solve the same problem, but which differ in various ways (such
|
||||||
|
as in their handling of numbers with leading zeroes). This algorithm
|
||||||
|
does not purport to precisely match the behavior of any particular other
|
||||||
|
algorithm, only to produce a simple and satisfying result for Rust formatting.
|
||||||
|
In particular, this algorithm aims to produce a satisfying result for a set of
|
||||||
|
symbols that have the same number of leading zeroes, and an acceptable and
|
||||||
|
easily understandable result for a set of symbols that has varying numbers of
|
||||||
|
leading zeroes.
|
||||||
|
|
||||||
|
As an example, version-sorting will sort the following strings in the order
|
||||||
|
given:
|
||||||
|
- `_ZYWX`
|
||||||
|
- `u_zzz`
|
||||||
|
- `u8`
|
||||||
|
- `u16`
|
||||||
|
- `u32`
|
||||||
|
- `u64`
|
||||||
|
- `u128`
|
||||||
|
- `u256`
|
||||||
|
- `ua`
|
||||||
|
- `usize`
|
||||||
|
- `uz`
|
||||||
|
- `v000`
|
||||||
|
- `v00`
|
||||||
|
- `v0`
|
||||||
|
- `v0s`
|
||||||
|
- `v00t`
|
||||||
|
- `v0u`
|
||||||
|
- `v001`
|
||||||
|
- `v01`
|
||||||
|
- `v1`
|
||||||
|
- `v009`
|
||||||
|
- `v09`
|
||||||
|
- `v9`
|
||||||
|
- `v010`
|
||||||
|
- `v10`
|
||||||
|
- `w005s09t`
|
||||||
|
- `w5s009t`
|
||||||
|
- `x64`
|
||||||
|
- `x86`
|
||||||
|
- `x86_32`
|
||||||
|
- `x86_64`
|
||||||
|
- `x86_128`
|
||||||
|
- `x87`
|
||||||
|
- `Z_YWX`
|
||||||
|
- `ZY_WX`
|
||||||
|
- `ZYW_X`
|
||||||
|
- `ZYWX`
|
||||||
|
- `ZYWX_`
|
||||||
|
|
||||||
### [Module-level items](items.md)
|
### [Module-level items](items.md)
|
||||||
|
|
||||||
### [Statements](statements.md)
|
### [Statements](statements.md)
|
||||||
|
|
|
@ -8,11 +8,11 @@ Put a blank line between the last key-value pair in a section and the header of
|
||||||
the next section. Do not place a blank line between section headers and the
|
the next section. Do not place a blank line between section headers and the
|
||||||
key-value pairs in that section, or between key-value pairs in a section.
|
key-value pairs in that section, or between key-value pairs in a section.
|
||||||
|
|
||||||
Sort key names alphabetically within each section, with the exception of the
|
Version-sort key names within each section, with the exception of the
|
||||||
`[package]` section. Put the `[package]` section at the top of the file; put
|
`[package]` section. Put the `[package]` section at the top of the file; put
|
||||||
the `name` and `version` keys in that order at the top of that section,
|
the `name` and `version` keys in that order at the top of that section,
|
||||||
followed by the remaining keys other than `description` in alphabetical order,
|
followed by the remaining keys other than `description` in order, followed by
|
||||||
followed by the `description` at the end of that section.
|
the `description` at the end of that section.
|
||||||
|
|
||||||
Don't use quotes around any standard key names; use bare keys. Only use quoted
|
Don't use quotes around any standard key names; use bare keys. Only use quoted
|
||||||
keys for non-standard keys whose names require them, and avoid introducing such
|
keys for non-standard keys whose names require them, and avoid introducing such
|
||||||
|
|
|
@ -37,6 +37,8 @@ history of the style guide. Notable changes in the Rust 2024 style edition
|
||||||
include:
|
include:
|
||||||
|
|
||||||
- Miscellaneous `rustfmt` bugfixes.
|
- Miscellaneous `rustfmt` bugfixes.
|
||||||
|
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
|
||||||
|
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
|
||||||
|
|
||||||
## Rust 2015/2018/2021 style edition
|
## Rust 2015/2018/2021 style edition
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ an item appears at module level or within another item.
|
||||||
alphabetically.
|
alphabetically.
|
||||||
|
|
||||||
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
|
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
|
||||||
must come before other items. Put imports before module declarations. Sort each
|
must come before other items. Put imports before module declarations.
|
||||||
alphabetically, except that `self` and `super` must come before any other
|
Version-sort each, except that `self` and `super` must come before any other
|
||||||
names.
|
names.
|
||||||
|
|
||||||
Don't automatically move module declarations annotated with `#[macro_use]`,
|
Don't automatically move module declarations annotated with `#[macro_use]`,
|
||||||
|
@ -467,8 +467,10 @@ foo::{
|
||||||
A *group* of imports is a set of imports on the same or sequential lines. One or
|
A *group* of imports is a set of imports on the same or sequential lines. One or
|
||||||
more blank lines or other items (e.g., a function) separate groups of imports.
|
more blank lines or other items (e.g., a function) separate groups of imports.
|
||||||
|
|
||||||
Within a group of imports, imports must be sorted ASCIIbetically (uppercase
|
Within a group of imports, imports must be version-sorted, except that
|
||||||
before lowercase). Groups of imports must not be merged or re-ordered.
|
non-lowercase characters (characters that can start an `UpperCamelCase`
|
||||||
|
identifier) must be sorted before lowercase characters. Groups of imports must
|
||||||
|
not be merged or re-ordered.
|
||||||
|
|
||||||
E.g., input:
|
E.g., input:
|
||||||
|
|
||||||
|
@ -495,10 +497,15 @@ re-ordering.
|
||||||
|
|
||||||
### Ordering list import
|
### Ordering list import
|
||||||
|
|
||||||
Names in a list import must be sorted ASCIIbetically, but with `self` and
|
Names in a list import must be version-sorted, except that:
|
||||||
`super` first, and groups and glob imports last. This applies recursively. For
|
- `self` and `super` always come first if present,
|
||||||
example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
|
- non-lowercase characters (characters that can start an `UpperCamelCase`
|
||||||
`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
|
identifier) must be sorted before lowercase characters, and
|
||||||
|
- groups and glob imports always come last if present.
|
||||||
|
|
||||||
|
This applies recursively. For example, `a::*` comes before `b::a` but `a::b`
|
||||||
|
comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z},
|
||||||
|
b::{self, r, s}};`.
|
||||||
|
|
||||||
### Normalisation
|
### Normalisation
|
||||||
|
|
||||||
|
|
|
@ -455,7 +455,7 @@ pub fn report_msg<'tcx>(
|
||||||
let sess = machine.tcx.sess;
|
let sess = machine.tcx.sess;
|
||||||
let level = match diag_level {
|
let level = match diag_level {
|
||||||
DiagLevel::Error => Level::Error,
|
DiagLevel::Error => Level::Error,
|
||||||
DiagLevel::Warning => Level::Warning(None),
|
DiagLevel::Warning => Level::Warning,
|
||||||
DiagLevel::Note => Level::Note,
|
DiagLevel::Note => Level::Note,
|
||||||
};
|
};
|
||||||
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);
|
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);
|
||||||
|
|
|
@ -446,7 +446,7 @@ mod tests {
|
||||||
Some(ignore_list),
|
Some(ignore_list),
|
||||||
);
|
);
|
||||||
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
|
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
|
||||||
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
||||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
|
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
|
||||||
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
|
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
|
||||||
|
@ -470,7 +470,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
|
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
|
||||||
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
||||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
|
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
|
||||||
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
|
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
|
||||||
|
@ -507,8 +507,8 @@ mod tests {
|
||||||
);
|
);
|
||||||
let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||||
let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
|
let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
|
||||||
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span));
|
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
|
||||||
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span));
|
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
|
||||||
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
|
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
|
||||||
emitter.emit_diagnostic(&bar_diagnostic);
|
emitter.emit_diagnostic(&bar_diagnostic);
|
||||||
emitter.emit_diagnostic(&foo_diagnostic);
|
emitter.emit_diagnostic(&foo_diagnostic);
|
||||||
|
|
125
tests/ui-fulldeps/stable-mir/check_trait_queries.rs
Normal file
125
tests/ui-fulldeps/stable-mir/check_trait_queries.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// run-pass
|
||||||
|
//! Test that users are able to retrieve information about trait declarations and implementations.
|
||||||
|
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-cross-compile
|
||||||
|
// ignore-remote
|
||||||
|
// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
|
|
||||||
|
extern crate rustc_middle;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rustc_smir;
|
||||||
|
extern crate rustc_driver;
|
||||||
|
extern crate rustc_interface;
|
||||||
|
extern crate stable_mir;
|
||||||
|
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
use rustc_smir::rustc_internal;
|
||||||
|
use stable_mir::CrateDef;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
const CRATE_NAME: &str = "trait_test";
|
||||||
|
|
||||||
|
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||||
|
fn test_traits() -> ControlFlow<()> {
|
||||||
|
let local_crate = stable_mir::local_crate();
|
||||||
|
let local_traits = local_crate.trait_decls();
|
||||||
|
assert_eq!(local_traits.len(), 1, "Expected `Max` trait, but found {:?}", local_traits);
|
||||||
|
assert_eq!(&local_traits[0].name(), "Max");
|
||||||
|
|
||||||
|
let local_impls = local_crate.trait_impls();
|
||||||
|
let impl_names = local_impls.iter().map(|trait_impl| trait_impl.name()).collect::<HashSet<_>>();
|
||||||
|
assert_impl(&impl_names, "<Positive as Max>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::marker::Copy>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::clone::Clone>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::fmt::Debug>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::cmp::PartialEq>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::cmp::Eq>");
|
||||||
|
assert_impl(&impl_names, "<Positive as std::convert::TryFrom<u64>>");
|
||||||
|
assert_impl(&impl_names, "<u64 as Max>");
|
||||||
|
assert_impl(&impl_names, "<impl std::convert::From<Positive> for u64>");
|
||||||
|
|
||||||
|
let all_traits = stable_mir::all_trait_decls();
|
||||||
|
assert!(all_traits.len() > local_traits.len());
|
||||||
|
assert!(
|
||||||
|
local_traits.iter().all(|t| all_traits.contains(t)),
|
||||||
|
"Local: {local_traits:#?}, All: {all_traits:#?}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let all_impls = stable_mir::all_trait_impls();
|
||||||
|
assert!(all_impls.len() > local_impls.len());
|
||||||
|
assert!(
|
||||||
|
local_impls.iter().all(|t| all_impls.contains(t)),
|
||||||
|
"Local: {local_impls:#?}, All: {all_impls:#?}"
|
||||||
|
);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_impl(impl_names: &HashSet<String>, target: &str) {
|
||||||
|
assert!(
|
||||||
|
impl_names.contains(target),
|
||||||
|
"Failed to find `{target}`. Implementations available: {impl_names:?}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This test will generate and analyze a dummy crate using the stable mir.
|
||||||
|
/// For that, it will first write the dummy crate into a file.
|
||||||
|
/// Then it will create a `StableMir` using custom arguments and then
|
||||||
|
/// it will run the compiler.
|
||||||
|
fn main() {
|
||||||
|
let path = "trait_queries.rs";
|
||||||
|
generate_input(&path).unwrap();
|
||||||
|
let args = vec![
|
||||||
|
"rustc".to_string(),
|
||||||
|
"--crate-type=lib".to_string(),
|
||||||
|
"--crate-name".to_string(),
|
||||||
|
CRATE_NAME.to_string(),
|
||||||
|
path.to_string(),
|
||||||
|
];
|
||||||
|
run!(args, test_traits()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
|
let mut file = std::fs::File::create(path)?;
|
||||||
|
write!(
|
||||||
|
file,
|
||||||
|
r#"
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Positive(u64);
|
||||||
|
|
||||||
|
impl TryFrom<u64> for Positive {{
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(val: u64) -> Result<Positive, Self::Error> {{
|
||||||
|
if val > 0 {{ Ok(Positive(val)) }} else {{ Err(()) }}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl From<Positive> for u64 {{
|
||||||
|
fn from(val: Positive) -> u64 {{ val.0 }}
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub trait Max {{
|
||||||
|
fn is_max(&self) -> bool;
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Max for u64 {{
|
||||||
|
fn is_max(&self) -> bool {{ *self == u64::MAX }}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Max for Positive {{
|
||||||
|
fn is_max(&self) -> bool {{ self.0.is_max() }}
|
||||||
|
}}
|
||||||
|
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
13
tests/ui/pattern/usefulness/issue-119493-type-error-ice.rs
Normal file
13
tests/ui/pattern/usefulness/issue-119493-type-error-ice.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct Foo(NonExistent);
|
||||||
|
//~^ ERROR cannot find type
|
||||||
|
//~| ERROR cannot find type
|
||||||
|
|
||||||
|
type U = impl Copy;
|
||||||
|
//~^ ERROR `impl Trait` in type aliases is unstable
|
||||||
|
let foo: U = Foo(());
|
||||||
|
let Foo(()) = foo;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
error[E0412]: cannot find type `NonExistent` in this scope
|
||||||
|
--> $DIR/issue-119493-type-error-ice.rs:5:16
|
||||||
|
|
|
||||||
|
LL | struct Foo(NonExistent);
|
||||||
|
| ^^^^^^^^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `NonExistent` in this scope
|
||||||
|
--> $DIR/issue-119493-type-error-ice.rs:5:16
|
||||||
|
|
|
||||||
|
LL | struct Foo(NonExistent);
|
||||||
|
| ^^^^^^^^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might be missing a type parameter
|
||||||
|
|
|
||||||
|
LL | struct Foo<NonExistent>(NonExistent);
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
|
error[E0658]: `impl Trait` in type aliases is unstable
|
||||||
|
--> $DIR/issue-119493-type-error-ice.rs:9:14
|
||||||
|
|
|
||||||
|
LL | type U = impl Copy;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
|
||||||
|
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0412, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0412`.
|
13
tests/ui/pattern/usefulness/issue-119778-type-error-ice.rs
Normal file
13
tests/ui/pattern/usefulness/issue-119778-type-error-ice.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct Foo([u8; S]);
|
||||||
|
//~^ ERROR cannot find value `S`
|
||||||
|
//~| ERROR cannot find value `S`
|
||||||
|
|
||||||
|
type U = impl Copy;
|
||||||
|
//~^ ERROR `impl Trait` in type aliases is unstable
|
||||||
|
let foo: U = Foo(());
|
||||||
|
let Foo(()) = foo;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
error[E0425]: cannot find value `S` in this scope
|
||||||
|
--> $DIR/issue-119778-type-error-ice.rs:5:21
|
||||||
|
|
|
||||||
|
LL | struct Foo([u8; S]);
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might be missing a const parameter
|
||||||
|
|
|
||||||
|
LL | struct Foo<const S: /* Type */>([u8; S]);
|
||||||
|
| +++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `S` in this scope
|
||||||
|
--> $DIR/issue-119778-type-error-ice.rs:5:21
|
||||||
|
|
|
||||||
|
LL | struct Foo([u8; S]);
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might be missing a const parameter
|
||||||
|
|
|
||||||
|
LL | struct Foo<const S: /* Type */>([u8; S]);
|
||||||
|
| +++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0658]: `impl Trait` in type aliases is unstable
|
||||||
|
--> $DIR/issue-119778-type-error-ice.rs:9:14
|
||||||
|
|
|
||||||
|
LL | type U = impl Copy;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
|
||||||
|
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0425`.
|
|
@ -6,9 +6,7 @@ type Pointer<T> = impl std::ops::Deref<Target = T>;
|
||||||
|
|
||||||
fn test() -> Pointer<_> {
|
fn test() -> Pointer<_> {
|
||||||
//~^ ERROR: the placeholder `_` is not allowed within types
|
//~^ ERROR: the placeholder `_` is not allowed within types
|
||||||
//~| ERROR: non-defining opaque type use in defining scope
|
|
||||||
Box::new(1)
|
Box::new(1)
|
||||||
//~^ ERROR expected generic type parameter, found `i32`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> {
|
||||||
| | not allowed in type signatures
|
| | not allowed in type signatures
|
||||||
| help: replace with the correct return type: `Pointer<i32>`
|
| help: replace with the correct return type: `Pointer<i32>`
|
||||||
|
|
||||||
error[E0792]: non-defining opaque type use in defining scope
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/issue-77179.rs:7:14
|
|
||||||
|
|
|
||||||
LL | fn test() -> Pointer<_> {
|
|
||||||
| ^^^^^^^^^^ argument `i32` is not a generic parameter
|
|
||||||
|
|
|
||||||
note: for this opaque type
|
|
||||||
--> $DIR/issue-77179.rs:5:19
|
|
||||||
|
|
|
||||||
LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0792]: expected generic type parameter, found `i32`
|
For more information about this error, try `rustc --explain E0121`.
|
||||||
--> $DIR/issue-77179.rs:10:5
|
|
||||||
|
|
|
||||||
LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
|
|
||||||
| - this generic parameter must be used with a generic type parameter
|
|
||||||
...
|
|
||||||
LL | Box::new(1)
|
|
||||||
| ^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0121, E0792.
|
|
||||||
For more information about an error, try `rustc --explain E0121`.
|
|
||||||
|
|
|
@ -744,6 +744,12 @@ style-team = [
|
||||||
"@yaahc",
|
"@yaahc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
project-const-traits = [
|
||||||
|
"@compiler-errors",
|
||||||
|
"@fee1-dead",
|
||||||
|
"@fmease",
|
||||||
|
"@oli-obk",
|
||||||
|
]
|
||||||
project-stable-mir = [
|
project-stable-mir = [
|
||||||
"@celinval",
|
"@celinval",
|
||||||
"@oli-obk",
|
"@oli-obk",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue