mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
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
@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
let mut failed = false;
|
||||
|
||||
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 re_static = tcx.lifetimes.re_static;
|
||||
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
|
||||
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 {
|
||||
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) {
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
Some(ast::ItemKind::MacCall(_)) => Level::Warning(None),
|
||||
Some(ast::ItemKind::MacCall(_)) => Level::Warning,
|
||||
_ => Level::Error,
|
||||
};
|
||||
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
|
||||
|
@ -417,7 +417,7 @@ fn report_inline_asm(
|
||||
}
|
||||
let level = match level {
|
||||
llvm::DiagnosticLevel::Error => Level::Error,
|
||||
llvm::DiagnosticLevel::Warning => Level::Warning(None),
|
||||
llvm::DiagnosticLevel::Warning => Level::Warning,
|
||||
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
||||
};
|
||||
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
|
||||
|
@ -1847,14 +1847,9 @@ impl SharedEmitterMain {
|
||||
dcx.emit_diagnostic(d);
|
||||
}
|
||||
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
|
||||
let err_level = match level {
|
||||
Level::Error => Level::Error,
|
||||
Level::Warning(_) => Level::Warning(None),
|
||||
Level::Note => Level::Note,
|
||||
_ => bug!("Invalid inline asm diagnostic level"),
|
||||
};
|
||||
assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
|
||||
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 cookie != 0 {
|
||||
|
@ -87,7 +87,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
|
||||
fn annotation_type_for_level(level: Level) -> AnnotationType {
|
||||
match level {
|
||||
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::Help | Level::OnceHelp => AnnotationType::Help,
|
||||
// FIXME(#59346): Not sure how to map this level
|
||||
|
@ -152,7 +152,6 @@ pub enum DiagnosticId {
|
||||
name: String,
|
||||
/// Indicates whether this lint should show up in cargo's future breakage report.
|
||||
has_future_breakage: bool,
|
||||
is_force_warn: bool,
|
||||
},
|
||||
}
|
||||
|
||||
@ -248,7 +247,8 @@ impl Diagnostic {
|
||||
true
|
||||
}
|
||||
|
||||
Level::Warning(_)
|
||||
Level::ForceWarning(_)
|
||||
| Level::Warning
|
||||
| Level::Note
|
||||
| Level::OnceNote
|
||||
| Level::Help
|
||||
@ -262,7 +262,7 @@ impl Diagnostic {
|
||||
&mut self,
|
||||
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
|
||||
{
|
||||
if expectation_id.is_stable() {
|
||||
@ -292,8 +292,11 @@ impl Diagnostic {
|
||||
}
|
||||
|
||||
pub(crate) fn is_force_warn(&self) -> bool {
|
||||
match self.code {
|
||||
Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
|
||||
match self.level {
|
||||
Level::ForceWarning(_) => {
|
||||
assert!(self.is_lint);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -472,7 +475,7 @@ impl Diagnostic {
|
||||
/// Add a warning attached to this diagnostic.
|
||||
#[rustc_lint_diagnostics]
|
||||
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
|
||||
}
|
||||
|
||||
@ -484,7 +487,7 @@ impl Diagnostic {
|
||||
sp: S,
|
||||
msg: impl Into<SubdiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Warning(None), msg, sp.into());
|
||||
self.sub(Level::Warning, msg, sp.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ impl Emitter for JsonEmitter {
|
||||
.into_iter()
|
||||
.map(|mut diag| {
|
||||
if diag.level == crate::Level::Allow {
|
||||
diag.level = crate::Level::Warning(None);
|
||||
diag.level = crate::Level::Warning;
|
||||
}
|
||||
FutureBreakageItem {
|
||||
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
|
||||
|
@ -420,6 +420,7 @@ pub struct DiagCtxt {
|
||||
/// as well as inconsistent state observation.
|
||||
struct DiagCtxtInner {
|
||||
flags: DiagCtxtFlags,
|
||||
|
||||
/// The number of lint errors that have been emitted.
|
||||
lint_err_count: usize,
|
||||
/// 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
|
||||
/// compilation ends.
|
||||
err_count: usize,
|
||||
warn_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>,
|
||||
span_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.
|
||||
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
|
||||
|
||||
/// The warning count, used for a recap upon finishing
|
||||
deduplicated_warn_count: usize,
|
||||
|
||||
future_breakage_diagnostics: Vec<Diagnostic>,
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
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 _));
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
@ -547,8 +550,7 @@ impl Drop for DiagCtxtInner {
|
||||
// instead of "require some error happened". Sadly that isn't ideal, as
|
||||
// lints can be `#[allow]`'d, potentially leading to this triggering.
|
||||
// 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 !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
|
||||
if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
|
||||
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
|
||||
self.flush_delayed(
|
||||
bugs,
|
||||
@ -594,9 +596,9 @@ impl DiagCtxt {
|
||||
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
||||
lint_err_count: 0,
|
||||
err_count: 0,
|
||||
warn_count: 0,
|
||||
deduplicated_err_count: 0,
|
||||
deduplicated_warn_count: 0,
|
||||
has_printed: false,
|
||||
emitter,
|
||||
span_delayed_bugs: Vec::new(),
|
||||
good_path_delayed_bugs: Vec::new(),
|
||||
@ -647,10 +649,11 @@ impl DiagCtxt {
|
||||
/// the overall count of emitted error diagnostics.
|
||||
pub fn reset_err_count(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.lint_err_count = 0;
|
||||
inner.err_count = 0;
|
||||
inner.warn_count = 0;
|
||||
inner.deduplicated_err_count = 0;
|
||||
inner.deduplicated_warn_count = 0;
|
||||
inner.has_printed = false;
|
||||
|
||||
// actually free the underlying memory (which `clear` would not do)
|
||||
inner.span_delayed_bugs = Default::default();
|
||||
@ -669,16 +672,11 @@ impl DiagCtxt {
|
||||
let key = (span.with_parent(None), key);
|
||||
|
||||
if diag.is_error() {
|
||||
if diag.level == Error && diag.is_lint {
|
||||
if diag.is_lint {
|
||||
inner.lint_err_count += 1;
|
||||
} else {
|
||||
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
|
||||
@ -693,15 +691,11 @@ impl DiagCtxt {
|
||||
let key = (span.with_parent(None), key);
|
||||
let diag = inner.stashed_diagnostics.remove(&key)?;
|
||||
if diag.is_error() {
|
||||
if diag.level == Error && diag.is_lint {
|
||||
if diag.is_lint {
|
||||
inner.lint_err_count -= 1;
|
||||
} else {
|
||||
inner.err_count -= 1;
|
||||
}
|
||||
} else {
|
||||
if diag.is_force_warn() {
|
||||
inner.warn_count -= 1;
|
||||
}
|
||||
}
|
||||
Some(DiagnosticBuilder::new_diagnostic(self, diag))
|
||||
}
|
||||
@ -738,7 +732,7 @@ impl DiagCtxt {
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
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`.
|
||||
@ -1005,7 +999,7 @@ impl DiagCtxt {
|
||||
(0, 0) => return,
|
||||
(0, _) => inner
|
||||
.emitter
|
||||
.emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))),
|
||||
.emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))),
|
||||
(_, 0) => {
|
||||
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
|
||||
}
|
||||
@ -1094,7 +1088,7 @@ impl DiagCtxt {
|
||||
&'a self,
|
||||
warning: impl IntoDiagnostic<'a, ()>,
|
||||
) -> DiagnosticBuilder<'a, ()> {
|
||||
warning.into_diagnostic(self, Warning(None))
|
||||
warning.into_diagnostic(self, Warning)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@ -1241,21 +1235,17 @@ impl DiagCtxtInner {
|
||||
for diag in diags {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
if diag.level == Error && diag.is_lint {
|
||||
if diag.is_lint {
|
||||
self.lint_err_count -= 1;
|
||||
} else {
|
||||
self.err_count -= 1;
|
||||
}
|
||||
} else {
|
||||
if diag.is_force_warn() {
|
||||
self.warn_count -= 1;
|
||||
} else {
|
||||
// Unless they're forced, don't flush stashed warnings when
|
||||
// there are errors, to avoid causing warning overload. The
|
||||
// stash would've been stolen already if it were important.
|
||||
if has_errors {
|
||||
continue;
|
||||
}
|
||||
// Unless they're forced, don't flush stashed warnings when
|
||||
// there are errors, to avoid causing warning overload. The
|
||||
// stash would've been stolen already if it were important.
|
||||
if !diag.is_force_warn() && has_errors {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let reported_this = self.emit_diagnostic(diag);
|
||||
@ -1304,23 +1294,20 @@ impl DiagCtxtInner {
|
||||
self.fulfilled_expectations.insert(expectation_id.normalize());
|
||||
}
|
||||
|
||||
if matches!(diagnostic.level, Warning(_))
|
||||
&& !self.flags.can_emit_warnings
|
||||
&& !diagnostic.is_force_warn()
|
||||
{
|
||||
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
|
||||
if diagnostic.has_future_breakage() {
|
||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
|
||||
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
if matches!(diagnostic.level, Expect(_) | Allow) {
|
||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
|
||||
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut guaranteed = None;
|
||||
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |mut diagnostic| {
|
||||
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
|
||||
if let Some(ref code) = diagnostic.code {
|
||||
self.emitted_diagnostic_codes.insert(code.clone());
|
||||
}
|
||||
@ -1359,12 +1346,13 @@ impl DiagCtxtInner {
|
||||
self.emitter.emit_diagnostic(&diagnostic);
|
||||
if diagnostic.is_error() {
|
||||
self.deduplicated_err_count += 1;
|
||||
} else if let Warning(_) = diagnostic.level {
|
||||
} else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
|
||||
self.deduplicated_warn_count += 1;
|
||||
}
|
||||
self.has_printed = true;
|
||||
}
|
||||
if diagnostic.is_error() {
|
||||
if diagnostic.level == Error && diagnostic.is_lint {
|
||||
if diagnostic.is_lint {
|
||||
self.bump_lint_err_count();
|
||||
} else {
|
||||
self.bump_err_count();
|
||||
@ -1374,8 +1362,6 @@ impl DiagCtxtInner {
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
fn bump_warn_count(&mut self) {
|
||||
self.warn_count += 1;
|
||||
}
|
||||
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.treat_err_as_bug() {
|
||||
match (
|
||||
@ -1562,14 +1544,17 @@ pub enum Level {
|
||||
/// Its `EmissionGuarantee` is `ErrorGuaranteed`.
|
||||
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.
|
||||
///
|
||||
/// 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 `()`.
|
||||
Warning(Option<LintExpectationId>),
|
||||
Warning,
|
||||
|
||||
/// A message giving additional context. Rare, because notes are more commonly attached to other
|
||||
/// diagnostics such as errors.
|
||||
@ -1622,7 +1607,7 @@ impl Level {
|
||||
Bug | DelayedBug | Fatal | Error => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
}
|
||||
Warning(_) => {
|
||||
ForceWarning(_) | Warning => {
|
||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||
}
|
||||
Note | OnceNote => {
|
||||
@ -1641,7 +1626,7 @@ impl Level {
|
||||
match self {
|
||||
Bug | DelayedBug => "error: internal compiler error",
|
||||
Fatal | Error => "error",
|
||||
Warning(_) => "warning",
|
||||
ForceWarning(_) | Warning => "warning",
|
||||
Note | OnceNote => "note",
|
||||
Help | OnceHelp => "help",
|
||||
FailureNote => "failure-note",
|
||||
@ -1655,7 +1640,7 @@ impl Level {
|
||||
|
||||
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
||||
match self {
|
||||
Expect(id) | Warning(Some(id)) => Some(*id),
|
||||
Expect(id) | ForceWarning(Some(id)) => Some(*id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ impl ToInternal<rustc_errors::Level> for Level {
|
||||
fn to_internal(self) -> rustc_errors::Level {
|
||||
match self {
|
||||
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::Help => rustc_errors::Level::Help,
|
||||
_ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
|
||||
|
@ -2405,6 +2405,39 @@ impl<'hir> Ty<'hir> {
|
||||
my_visitor.visit_ty(self);
|
||||
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`.
|
||||
@ -2735,7 +2768,7 @@ pub enum FnRetTy<'hir> {
|
||||
Return(&'hir Ty<'hir>),
|
||||
}
|
||||
|
||||
impl FnRetTy<'_> {
|
||||
impl<'hir> FnRetTy<'hir> {
|
||||
#[inline]
|
||||
pub fn span(&self) -> Span {
|
||||
match *self {
|
||||
@ -2743,6 +2776,15 @@ impl FnRetTy<'_> {
|
||||
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
|
||||
|
@ -642,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_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();
|
||||
visitor.visit_item(it);
|
||||
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) => {
|
||||
tcx.ensure().type_of(def_id);
|
||||
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: _;`.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
@ -726,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
||||
}
|
||||
hir::ImplItemKind::Const(ty, _) => {
|
||||
// Account for `const T: _ = ..;`
|
||||
if !is_suggestable_infer_ty(ty) {
|
||||
if !ty.is_suggestable_infer_ty() {
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_impl_item(impl_item);
|
||||
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))]
|
||||
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
|
||||
use rustc_hir::Node::*;
|
||||
@ -1188,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
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) => {
|
||||
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||
// 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::{Span, DUMMY_SP};
|
||||
|
||||
use super::bad_placeholder;
|
||||
use super::ItemCtxt;
|
||||
use super::{bad_placeholder, is_suggestable_infer_ty};
|
||||
pub use opaque::test_opaque_hidden_types;
|
||||
|
||||
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
|
||||
.and_then(|body_id| {
|
||||
is_suggestable_infer_ty(ty).then(|| {
|
||||
ty.is_suggestable_infer_ty().then(|| {
|
||||
infer_placeholder_type(
|
||||
tcx,
|
||||
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)
|
||||
}
|
||||
ImplItemKind::Const(ty, body_id) => {
|
||||
if is_suggestable_infer_ty(ty) {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
tcx,
|
||||
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 {
|
||||
ItemKind::Static(ty, .., body_id) => {
|
||||
if is_suggestable_infer_ty(ty) {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
tcx,
|
||||
def_id,
|
||||
@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||
}
|
||||
}
|
||||
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")
|
||||
} else {
|
||||
icx.to_ty(ty)
|
||||
@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>(
|
||||
}
|
||||
|
||||
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 => {
|
||||
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) {
|
||||
|
@ -134,6 +134,21 @@ impl TaitConstraintLocator<'_> {
|
||||
debug!("no constraint: no typeck results");
|
||||
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
|
||||
// const-checking, avoid calling it if we don't have to.
|
||||
// ```rust
|
||||
|
@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>(
|
||||
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
|
||||
|
||||
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)
|
||||
} else {
|
||||
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::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||
ty::Projection | ty::Inherent => {
|
||||
format!("the associated type `{p}`")
|
||||
}
|
||||
ty::AliasKind::Weak => format!("the type alias `{p}`"),
|
||||
ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
|
||||
ty::Weak => format!("the type alias `{p}`"),
|
||||
ty::Opaque => format!("the opaque type `{p}`"),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -510,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||
));
|
||||
} else {
|
||||
match a_ty.kind() {
|
||||
&ty::Alias(ty::AliasKind::Projection, data) => {
|
||||
&ty::Alias(ty::Projection, data) => {
|
||||
// FIXME: This does not handle subtyping correctly, we could
|
||||
// instead create a new inference variable for `a_ty`, emitting
|
||||
// `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.
|
||||
ty::Alias(
|
||||
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
|
||||
_,
|
||||
) => return Err(TypeError::CyclicTy(a_ty)),
|
||||
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
|
||||
return Err(TypeError::CyclicTy(a_ty));
|
||||
}
|
||||
_ => 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
|
||||
//! 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::ty::tls;
|
||||
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<'_>) -> _));
|
||||
rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
|
||||
.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::{Integer, TagEncoding, Variants};
|
||||
use rustc_target::spec::abi::Abi as SpecAbi;
|
||||
use rustc_type_ir::DynKind;
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
|
||||
}
|
||||
match ty.kind() {
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
@ -787,7 +787,9 @@ LLVMRustOptimize(
|
||||
for (auto PluginPath: Plugins) {
|
||||
auto Plugin = PassPlugin::Load(PluginPath.str());
|
||||
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;
|
||||
}
|
||||
Plugin->registerPassBuilderCallbacks(PB);
|
||||
|
@ -312,8 +312,9 @@ pub fn struct_lint_level(
|
||||
// create a `DiagnosticBuilder` and continue as we would for warnings.
|
||||
rustc_errors::Level::Expect(expect_id)
|
||||
}
|
||||
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
|
||||
Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None),
|
||||
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::ForceWarning(Some(expect_id)),
|
||||
Level::ForceWarn(None) => rustc_errors::Level::ForceWarning(None),
|
||||
Level::Warn => rustc_errors::Level::Warning,
|
||||
Level::Deny | Level::Forbid => rustc_errors::Level::Error,
|
||||
};
|
||||
let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
|
||||
@ -350,22 +351,19 @@ pub fn struct_lint_level(
|
||||
// suppressed the lint due to macros.
|
||||
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
|
||||
// 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
|
||||
// the `Diagnostic`.
|
||||
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);
|
||||
err.emit();
|
||||
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 {
|
||||
let explanation = match future_incompatible.reason {
|
||||
FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
|
||||
|
@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||
|
||||
/// Whether this alias type is an opaque.
|
||||
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
|
||||
@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
// Extern types have metadata = ().
|
||||
| ty::Foreign(..)
|
||||
// `dyn*` has no metadata
|
||||
| ty::Dynamic(_, _, DynKind::DynStar)
|
||||
| ty::Dynamic(_, _, ty::DynStar)
|
||||
// If returned by `struct_tail_without_normalization` this is a unit struct
|
||||
// without any fields, or not a struct, and therefore is Sized.
|
||||
| ty::Adt(..)
|
||||
@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
| ty::Tuple(..) => (tcx.types.unit, 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);
|
||||
(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 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 {
|
||||
// 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 pat = self.lower_pattern(&cx, pat)?;
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ use std::fmt;
|
||||
use rustc_index::Idx;
|
||||
#[cfg(feature = "rustc")]
|
||||
use rustc_middle::ty::Ty;
|
||||
#[cfg(feature = "rustc")]
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use crate::constructor::{Constructor, ConstructorSet};
|
||||
#[cfg(feature = "rustc")]
|
||||
@ -52,6 +54,8 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
|
||||
pub trait TypeCx: Sized + fmt::Debug {
|
||||
/// The type of a pattern.
|
||||
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
|
||||
/// Errors that can abort analysis.
|
||||
type Error: fmt::Debug;
|
||||
/// The index of an enum variant.
|
||||
type VariantIdx: Clone + Idx;
|
||||
/// A string literal
|
||||
@ -73,7 +77,7 @@ pub trait TypeCx: Sized + fmt::Debug {
|
||||
/// The set of all the constructors for `ty`.
|
||||
///
|
||||
/// 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.
|
||||
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>,
|
||||
arms: &[rustc::MatchArm<'p, '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.
|
||||
let wildcard_arena = tycx.pattern_arena;
|
||||
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
|
||||
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
|
||||
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);
|
||||
|
||||
// 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
|
||||
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
|
||||
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_session::lint;
|
||||
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::errors::{
|
||||
@ -59,9 +59,13 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
||||
}
|
||||
|
||||
/// 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());
|
||||
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<'_> {
|
||||
@ -106,18 +110,18 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
||||
fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||
cx: MatchCtxt<'a, 'p, 'tcx>,
|
||||
column: &PatternColumn<'p, 'tcx>,
|
||||
) -> Vec<WitnessPat<'p, 'tcx>> {
|
||||
) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> {
|
||||
let Some(ty) = column.head_ty() else {
|
||||
return Vec::new();
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
||||
|
||||
let set = column.analyze_ctors(pcx);
|
||||
let set = column.analyze_ctors(pcx)?;
|
||||
if set.present.is_empty() {
|
||||
// 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),
|
||||
// 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();
|
||||
@ -137,7 +141,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||
let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
|
||||
for (i, col_i) in specialized_columns.iter().enumerate() {
|
||||
// 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, _, _)`,
|
||||
// adding enough wildcards to match `arity`.
|
||||
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>(
|
||||
@ -155,13 +159,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||
arms: &[MatchArm<'p, 'tcx>],
|
||||
pat_column: &PatternColumn<'p, 'tcx>,
|
||||
scrut_ty: RevealedTy<'tcx>,
|
||||
) {
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
|
||||
if !matches!(
|
||||
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
|
||||
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() {
|
||||
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
||||
// 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.
|
||||
@ -207,14 +212,14 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
|
||||
cx: MatchCtxt<'a, 'p, 'tcx>,
|
||||
column: &PatternColumn<'p, 'tcx>,
|
||||
) {
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let Some(ty) = column.head_ty() else {
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
let pcx = &PlaceCtxt::new_dummy(cx, ty);
|
||||
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(_)) {
|
||||
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.
|
||||
for ctor in set.present {
|
||||
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::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||
use smallvec::SmallVec;
|
||||
@ -302,7 +304,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||
///
|
||||
/// See [`crate::constructor`] for considerations of emptiness.
|
||||
#[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 make_uint_range = |start, end| {
|
||||
IntRange::from_range(
|
||||
@ -311,9 +316,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||
RangeEnd::Included,
|
||||
)
|
||||
};
|
||||
// Abort on type error.
|
||||
ty.error_reported()?;
|
||||
// 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.
|
||||
match ty.kind() {
|
||||
Ok(match ty.kind() {
|
||||
ty::Bool => ConstructorSet::Bool,
|
||||
ty::Char => {
|
||||
// The valid Unicode Scalar Value ranges.
|
||||
@ -423,7 +430,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||
ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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> {
|
||||
type Ty = RevealedTy<'tcx>;
|
||||
type Error = ErrorGuaranteed;
|
||||
type VariantIdx = VariantIdx;
|
||||
type StrLit = Const<'tcx>;
|
||||
type ArmData = HirId;
|
||||
@ -963,7 +971,10 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||
) -> &[Self::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)
|
||||
}
|
||||
|
||||
|
@ -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] {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -1336,14 +1336,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||
mcx: MatchCtxt<'a, 'p, Cx>,
|
||||
matrix: &mut Matrix<'p, Cx>,
|
||||
is_top_level: bool,
|
||||
) -> WitnessMatrix<Cx> {
|
||||
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
|
||||
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
||||
|
||||
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
|
||||
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
|
||||
// the file for details.
|
||||
return WitnessMatrix::empty();
|
||||
return Ok(WitnessMatrix::empty());
|
||||
}
|
||||
|
||||
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
|
||||
// useful.
|
||||
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
|
||||
// irrelevant.
|
||||
return if matrix.wildcard_row_is_relevant {
|
||||
WitnessMatrix::unit_witness()
|
||||
Ok(WitnessMatrix::unit_witness())
|
||||
} else {
|
||||
// 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.
|
||||
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 split_set = ctors_for_ty.split(pcx, ctors);
|
||||
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 witnesses = ensure_sufficient_stack(|| {
|
||||
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
|
||||
});
|
||||
})?;
|
||||
|
||||
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
|
||||
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.
|
||||
@ -1469,9 +1469,10 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||
arms: &[MatchArm<'p, Cx>],
|
||||
scrut_ty: Cx::Ty,
|
||||
scrut_validity: ValidityConstraint,
|
||||
) -> UsefulnessReport<'p, Cx> {
|
||||
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
|
||||
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 arm_usefulness: Vec<_> = arms
|
||||
@ -1488,5 +1489,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||
(arm, usefulness)
|
||||
})
|
||||
.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
|
||||
// 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
|
||||
|
||||
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
|
||||
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
|
||||
let future_incompatible = lint.future_incompatible.as_ref().unwrap();
|
||||
err.code(DiagnosticId::Lint {
|
||||
name: lint.name_lower(),
|
||||
has_future_breakage: false,
|
||||
is_force_warn: false,
|
||||
});
|
||||
err.code(DiagnosticId::Lint { name: lint.name_lower(), has_future_breakage: false });
|
||||
err.warn(lint.desc);
|
||||
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,
|
||||
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
|
||||
};
|
||||
use stable_mir::{CrateItem, DefId};
|
||||
use stable_mir::{CrateItem, CrateNum, DefId};
|
||||
|
||||
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 {
|
||||
type T = rustc_span::def_id::DefId;
|
||||
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,
|
||||
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::iter;
|
||||
|
||||
use crate::rustc_internal::{internal, RustcInternal};
|
||||
use crate::rustc_smir::builder::BodyBuilder;
|
||||
@ -67,10 +68,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
}
|
||||
|
||||
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();
|
||||
tables
|
||||
.tcx
|
||||
.traits(LOCAL_CRATE)
|
||||
.traits(crate_num.internal(&mut *tables))
|
||||
.iter()
|
||||
.map(|trait_def_id| tables.trait_def(*trait_def_id))
|
||||
.collect()
|
||||
@ -84,10 +90,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
}
|
||||
|
||||
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();
|
||||
tables
|
||||
.tcx
|
||||
.trait_impls_in_crate(LOCAL_CRATE)
|
||||
.trait_impls_in_crate(crate_num.internal(&mut *tables))
|
||||
.iter()
|
||||
.map(|impl_def_id| tables.impl_def(*impl_def_id))
|
||||
.collect()
|
||||
|
@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
|
||||
impl<'tcx> Stable<'tcx> for ty::AliasKind {
|
||||
type T = stable_mir::ty::AliasKind;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
use rustc_middle::ty::AliasKind::*;
|
||||
match self {
|
||||
Projection => stable_mir::ty::AliasKind::Projection,
|
||||
Inherent => stable_mir::ty::AliasKind::Inherent,
|
||||
Opaque => stable_mir::ty::AliasKind::Opaque,
|
||||
Weak => stable_mir::ty::AliasKind::Weak,
|
||||
ty::Projection => stable_mir::ty::AliasKind::Projection,
|
||||
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
|
||||
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
|
||||
ty::Weak => stable_mir::ty::AliasKind::Weak,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
|
||||
type T = stable_mir::ty::DynKind;
|
||||
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
use rustc_middle::ty::DynKind;
|
||||
match self {
|
||||
DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
|
||||
DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
|
||||
ty::Dyn => stable_mir::ty::DynKind::Dyn,
|
||||
ty::DynStar => stable_mir::ty::DynKind::DynStar,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,29 @@
|
||||
//! Doing this via a separate goal is called "deferred alias relation" and part
|
||||
//! of our more general approach to "lazy normalization".
|
||||
//!
|
||||
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
|
||||
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
|
||||
//! projection predicate with B as the right-hand side of the projection.
|
||||
//! This goal is computed in both directions, if both are aliases.
|
||||
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
|
||||
//! aliases with the same def-id.
|
||||
//! * 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
|
||||
//! performing them together. This is used specifically to resolve ambiguities.
|
||||
//! This is done by first normalizing both sides of the goal, ending up in
|
||||
//! either a concrete type, rigid projection, opaque, or an infer variable.
|
||||
//! These are related further according to the rules below:
|
||||
//!
|
||||
//! (1.) If we end up with a rigid projection and a rigid projection, then we
|
||||
//! relate those projections structurally.
|
||||
//!
|
||||
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
|
||||
//! 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 rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
self.relate(param_env, lhs, variance, rhs)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else if alias.is_opaque(tcx) {
|
||||
// FIXME: This doesn't account for variance.
|
||||
self.define_opaque(param_env, alias, rhs)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
self.relate(param_env, lhs, variance, rhs)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else if alias.is_opaque(tcx) {
|
||||
// FIXME: This doesn't account for variance.
|
||||
self.define_opaque(param_env, alias, lhs)
|
||||
} else {
|
||||
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.
|
||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||
fn try_normalize_term(
|
||||
|
@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
|
||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||
QueryResult, Response,
|
||||
};
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
||||
use rustc_middle::ty::{
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||
@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
return Some(ty);
|
||||
};
|
||||
|
||||
// We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
|
||||
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
|
||||
if let Some(def_id) = alias.def_id.as_local() {
|
||||
if self
|
||||
.unify_existing_opaque_tys(
|
||||
param_env,
|
||||
OpaqueTypeKey { def_id, args: alias.args },
|
||||
self.next_ty_infer(),
|
||||
)
|
||||
.is_empty()
|
||||
{
|
||||
return Some(ty);
|
||||
}
|
||||
// We do no always define opaque types eagerly to allow non-defining uses
|
||||
// in the defining scope. However, if we can unify this opaque to an existing
|
||||
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
|
||||
// through.
|
||||
if let DefineOpaqueTypes::No = define_opaque_types
|
||||
&& let Reveal::UserFacing = param_env.reveal()
|
||||
&& let ty::Opaque = kind
|
||||
&& let Some(def_id) = alias.def_id.as_local()
|
||||
&& self.can_define_opaque_ty(def_id)
|
||||
{
|
||||
if self
|
||||
.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,
|
||||
};
|
||||
use crate::{
|
||||
mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
|
||||
TraitDecls,
|
||||
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
|
||||
Symbol, TraitDecls,
|
||||
};
|
||||
|
||||
/// 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.
|
||||
fn has_body(&self, item: DefId) -> bool;
|
||||
fn all_trait_decls(&self) -> TraitDecls;
|
||||
fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
|
||||
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
|
||||
fn all_trait_impls(&self) -> ImplTraitDecls;
|
||||
fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
|
||||
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
|
||||
fn generics_of(&self, def_id: DefId) -> Generics;
|
||||
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::Body;
|
||||
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;
|
||||
#[macro_use]
|
||||
@ -86,6 +86,18 @@ pub struct Crate {
|
||||
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)]
|
||||
pub enum ItemKind {
|
||||
Fn,
|
||||
@ -169,18 +181,10 @@ pub fn all_trait_decls() -> TraitDecls {
|
||||
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 {
|
||||
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.
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Opaque(String);
|
||||
|
@ -714,9 +714,16 @@ crate_def! {
|
||||
}
|
||||
|
||||
crate_def! {
|
||||
/// A trait's definition.
|
||||
pub TraitDef;
|
||||
}
|
||||
|
||||
impl TraitDef {
|
||||
pub fn declaration(trait_def: &TraitDef) -> TraitDecl {
|
||||
with(|cx| cx.trait_decl(trait_def))
|
||||
}
|
||||
}
|
||||
|
||||
crate_def! {
|
||||
pub GenericDef;
|
||||
}
|
||||
@ -726,9 +733,17 @@ crate_def! {
|
||||
}
|
||||
|
||||
crate_def! {
|
||||
/// A trait impl definition.
|
||||
pub ImplDef;
|
||||
}
|
||||
|
||||
impl ImplDef {
|
||||
/// Retrieve information about this implementation.
|
||||
pub fn trait_impl(&self) -> ImplTrait {
|
||||
with(|cx| cx.trait_impl(self))
|
||||
}
|
||||
}
|
||||
|
||||
crate_def! {
|
||||
pub RegionDef;
|
||||
}
|
||||
|
@ -771,7 +771,11 @@ impl Ipv4Addr {
|
||||
|| self.is_loopback()
|
||||
|| self.is_link_local()
|
||||
// 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_benchmarking()
|
||||
|| self.is_reserved()
|
||||
@ -1515,8 +1519,12 @@ impl Ipv6Addr {
|
||||
// AS112-v6 (`2001:4:112::/48`)
|
||||
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
||||
// 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_unique_local()
|
||||
|| self.is_unicast_link_local())
|
||||
|
@ -461,6 +461,10 @@ fn ipv4_properties() {
|
||||
check!("198.18.54.2", benchmarking);
|
||||
check!("198.19.255.255", benchmarking);
|
||||
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.100");
|
||||
check!("240.0.0.0", reserved);
|
||||
@ -480,6 +484,10 @@ fn ipv6_properties() {
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($s:expr, &[$($octet:expr),*]) => {
|
||||
check!($s, &[$($octet),*], 0);
|
||||
};
|
||||
|
||||
($s:expr, &[$($octet:expr),*], $mask:expr) => {
|
||||
assert_eq!($s, ip!($s).to_string());
|
||||
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],
|
||||
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:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
|
||||
check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
|
||||
|
||||
check!(
|
||||
"2001:200::",
|
||||
@ -665,6 +673,8 @@ fn ipv6_properties() {
|
||||
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!(
|
||||
|
@ -383,8 +383,6 @@ impl<T: ?Sized> Mutex<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(mutex_unpoison)]
|
||||
///
|
||||
/// use std::sync::{Arc, Mutex};
|
||||
/// use std::thread;
|
||||
///
|
||||
@ -406,7 +404,7 @@ impl<T: ?Sized> Mutex<T> {
|
||||
/// assert_eq!(*x, 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "mutex_unpoison", issue = "96469")]
|
||||
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn clear_poison(&self) {
|
||||
self.poison.clear();
|
||||
}
|
||||
|
@ -387,8 +387,6 @@ impl<T: ?Sized> RwLock<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(mutex_unpoison)]
|
||||
///
|
||||
/// use std::sync::{Arc, RwLock};
|
||||
/// use std::thread;
|
||||
///
|
||||
@ -410,7 +408,7 @@ impl<T: ?Sized> RwLock<T> {
|
||||
/// assert_eq!(*guard, 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "mutex_unpoison", issue = "96469")]
|
||||
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn clear_poison(&self) {
|
||||
self.poison.clear();
|
||||
}
|
||||
|
@ -112,6 +112,90 @@ fn bar() {}
|
||||
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)
|
||||
|
||||
### [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
|
||||
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
|
||||
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 `description` at the end of that section.
|
||||
followed by the remaining keys other than `description` in order, followed by
|
||||
the `description` at the end of that section.
|
||||
|
||||
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
|
||||
|
@ -37,6 +37,8 @@ history of the style guide. Notable changes in the Rust 2024 style edition
|
||||
include:
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -9,8 +9,8 @@ an item appears at module level or within another item.
|
||||
alphabetically.
|
||||
|
||||
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
|
||||
must come before other items. Put imports before module declarations. Sort each
|
||||
alphabetically, except that `self` and `super` must come before any other
|
||||
must come before other items. Put imports before module declarations.
|
||||
Version-sort each, except that `self` and `super` must come before any other
|
||||
names.
|
||||
|
||||
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
|
||||
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
|
||||
before lowercase). Groups of imports must not be merged or re-ordered.
|
||||
Within a group of imports, imports must be version-sorted, except that
|
||||
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:
|
||||
|
||||
@ -495,10 +497,15 @@ re-ordering.
|
||||
|
||||
### Ordering list import
|
||||
|
||||
Names in a list import must be sorted ASCIIbetically, but with `self` and
|
||||
`super` first, and groups and glob imports last. 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}};`.
|
||||
Names in a list import must be version-sorted, except that:
|
||||
- `self` and `super` always come first if present,
|
||||
- non-lowercase characters (characters that can start an `UpperCamelCase`
|
||||
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
|
||||
|
||||
|
@ -455,7 +455,7 @@ pub fn report_msg<'tcx>(
|
||||
let sess = machine.tcx.sess;
|
||||
let level = match diag_level {
|
||||
DiagLevel::Error => Level::Error,
|
||||
DiagLevel::Warning => Level::Warning(None),
|
||||
DiagLevel::Warning => Level::Warning,
|
||||
DiagLevel::Note => Level::Note,
|
||||
};
|
||||
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);
|
||||
|
@ -446,7 +446,7 @@ mod tests {
|
||||
Some(ignore_list),
|
||||
);
|
||||
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);
|
||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
|
||||
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
|
||||
@ -470,7 +470,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
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);
|
||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
|
||||
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 foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
|
||||
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span));
|
||||
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span));
|
||||
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
|
||||
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
|
||||
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
|
||||
emitter.emit_diagnostic(&bar_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<_> {
|
||||
//~^ ERROR: the placeholder `_` is not allowed within types
|
||||
//~| ERROR: non-defining opaque type use in defining scope
|
||||
Box::new(1)
|
||||
//~^ ERROR expected generic type parameter, found `i32`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> {
|
||||
| | not allowed in type signatures
|
||||
| help: replace with the correct return type: `Pointer<i32>`
|
||||
|
||||
error[E0792]: non-defining opaque type use in defining scope
|
||||
--> $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: aborting due to 1 previous error
|
||||
|
||||
error[E0792]: expected generic type parameter, found `i32`
|
||||
--> $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`.
|
||||
For more information about this error, try `rustc --explain E0121`.
|
||||
|
@ -744,6 +744,12 @@ style-team = [
|
||||
"@yaahc",
|
||||
]
|
||||
|
||||
project-const-traits = [
|
||||
"@compiler-errors",
|
||||
"@fee1-dead",
|
||||
"@fmease",
|
||||
"@oli-obk",
|
||||
]
|
||||
project-stable-mir = [
|
||||
"@celinval",
|
||||
"@oli-obk",
|
||||
|
Loading…
Reference in New Issue
Block a user