diff options
54 files changed, 1116 insertions, 251 deletions
diff --git a/Cargo.lock b/Cargo.lock index a1bbc1dca76..fcd58d8a866 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4233,6 +4233,7 @@ dependencies = [ "rustc_hir", "rustc_middle", "rustc_span", + "rustc_target", "scoped-tls", "tracing", ] diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 096cea945b0..418e1df5857 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1300,14 +1300,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - AssocItemKind::Type(box TyAlias { - generics, - where_clauses, - where_predicates_split, - bounds, - ty, - .. - }) => { + AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => { if ty.is_none() { self.session.emit_err(errors::AssocTypeWithoutBody { span: item.span, @@ -1315,18 +1308,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } self.check_type_no_bounds(bounds, "`impl`s"); - if ty.is_some() { - self.check_gat_where( - item.id, - generics.where_clause.predicates.split_at(*where_predicates_split).0, - *where_clauses, - ); - } } _ => {} } } + if let AssocItemKind::Type(box TyAlias { + generics, + where_clauses, + where_predicates_split, + ty: Some(_), + .. + }) = &item.kind + { + self.check_gat_where( + item.id, + generics.where_clause.predicates.split_at(*where_predicates_split).0, + *where_clauses, + ); + } + if ctxt == AssocCtxt::Trait || self.in_trait_impl { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 00e6acb5c1a..a463dff852d 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -243,8 +243,16 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, _ => elf::EF_MIPS_ARCH_32R2, }; - // The only ABI LLVM supports for 32-bit MIPS CPUs is o32. - let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch; + + let mut e_flags = elf::EF_MIPS_CPIC | arch; + + // If the ABI is explicitly given, use it or default to O32. + match sess.target.options.llvm_abiname.to_lowercase().as_str() { + "n32" => e_flags |= elf::EF_MIPS_ABI2, + "o32" => e_flags |= elf::EF_MIPS_ABI_O32, + _ => e_flags |= elf::EF_MIPS_ABI_O32, + }; + if sess.target.options.relocation_model != RelocModel::Static { e_flags |= elf::EF_MIPS_PIC; } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 42f4531c0ef..69c8cc8c590 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -335,8 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_vars_with_obligations(expected); - + let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches // the `Some(5)` which is not of type Ref. @@ -353,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Preserve the reference type. We'll need it later during THIR lowering. pat_adjustments.push(expected); - expected = inner_ty; + expected = self.try_structurally_resolve_type(pat.span, inner_ty); def_bm = ty::BindByReference(match def_bm { // If default binding mode is by value, make it `ref` or `ref mut` // (depending on whether we observe `&` or `&mut`). @@ -627,6 +626,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { local_ty } + /// When a variable is bound several times in a `PatKind::Or`, it'll resolve all of the + /// subsequent bindings of the same name to the first usage. Verify that all of these + /// bindings have the same type by comparing them all against the type of that first pat. fn check_binding_alt_eq_ty( &self, ba: hir::BindingAnnotation, @@ -638,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let var_ty = self.local_ty(span, var_id); if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); - let var_ty = self.resolve_vars_with_obligations(var_ty); + let var_ty = self.resolve_vars_if_possible(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); err.span_label(hir.span(var_id), msg); let in_match = hir.parent_iter(var_id).any(|(_, n)| { @@ -656,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, span, var_ty, - self.resolve_vars_with_obligations(ty), + self.resolve_vars_if_possible(ty), ba, ); err.emit(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bb75ecc6adb..a90a41f5d70 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -162,10 +162,18 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte let mut infcx_inner = infcx.inner.borrow_mut(); let ty_vars = infcx_inner.type_variables(); let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind && !var_origin.span.from_expansion() { - Some(name) + let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); + let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); + let generic_param_def = generics.param_at(idx as usize, infcx.tcx); + if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind + { + None + } else { + Some(name) + } } else { None } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 1422bdc9ea2..b0e7cf23cae 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -464,52 +464,53 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, ) -> Option<TypeErrorAdditionalDiags> { let hir = self.tcx.hir(); - if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && - let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_sig, _, body_id), .. - }) = node { - let body = hir.body(*body_id); - - /// Find the if expression with given span - struct IfVisitor { - pub result: bool, - pub found_if: bool, - pub err_span: Span, - } + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) { + let body = hir.body(body_id); + + /// Find the if expression with given span + struct IfVisitor { + pub result: bool, + pub found_if: bool, + pub err_span: Span, + } - impl<'v> Visitor<'v> for IfVisitor { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - if self.result { return; } - match ex.kind { - hir::ExprKind::If(cond, _, _) => { - self.found_if = true; - walk_expr(self, cond); - self.found_if = false; + impl<'v> Visitor<'v> for IfVisitor { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.result { + return; + } + match ex.kind { + hir::ExprKind::If(cond, _, _) => { + self.found_if = true; + walk_expr(self, cond); + self.found_if = false; + } + _ => walk_expr(self, ex), } - _ => walk_expr(self, ex), } - } - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if let hir::StmtKind::Local(hir::Local { - span, pat: hir::Pat{..}, ty: None, init: Some(_), .. - }) = &ex.kind - && self.found_if - && span.eq(&self.err_span) { - self.result = true; + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + if let hir::StmtKind::Local(hir::Local { + span, pat: hir::Pat{..}, ty: None, init: Some(_), .. + }) = &ex.kind + && self.found_if + && span.eq(&self.err_span) { + self.result = true; + } + walk_stmt(self, ex); } - walk_stmt(self, ex); - } - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - hir::intravisit::walk_body(self, body); + fn visit_body(&mut self, body: &'v hir::Body<'v>) { + hir::intravisit::walk_body(self, body); + } } - } - let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; - visitor.visit_body(&body); - if visitor.result { - return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()}); + let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; + visitor.visit_body(&body); + if visitor.result { + return Some(TypeErrorAdditionalDiags::AddLetForLetChains { + span: span.shrink_to_lo(), + }); } } None diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fca32b73d1d..a123effd0f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -332,6 +332,39 @@ pub struct InferCtxt<'tcx> { next_trait_solver: bool, } +impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> { + fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> { + use InferTy::*; + match ty { + // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved + // ty infers will give you the universe of the var it resolved to not the universe + // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then + // try to print out `?0.1` it will just print `?0`. + TyVar(ty_vid) => match self.probe_ty_var(ty_vid) { + Err(universe) => Some(universe), + Ok(_) => None, + }, + IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => None, + } + } + + fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> { + use ty::InferConst::*; + match ct { + // Same issue as with `universe_of_ty` + Var(ct_vid) => match self.probe_const_var(ct_vid) { + Err(universe) => Some(universe), + Ok(_) => None, + }, + Fresh(_) => None, + } + } + + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { + Some(self.universe_of_region_vid(lt)) + } +} + /// See the `error_reporting` module for more details. #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub enum ValuePairs<'tcx> { @@ -1068,6 +1101,11 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().universe(r) } + /// Return the universe that the region variable `r` was created in. + pub fn universe_of_region_vid(&self, vid: ty::RegionVid) -> ty::UniverseIndex { + self.inner.borrow_mut().unwrap_region_constraints().var_universe(vid) + } + /// Number of region variables created so far. pub fn num_region_vars(&self) -> usize { self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 87c542dc2e2..a0f2e9aed81 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4084,7 +4084,7 @@ declare_lint! { /// /// ### Explanation /// - /// The preferred location for where clauses on associated types in impls + /// The preferred location for where clauses on associated types /// is after the type. However, for most of generic associated types development, /// it was only accepted before the equals. To provide a transition period and /// further evaluate this change, both are currently accepted. At some point in diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index a6bf7491118..5f2b6d42bf8 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; /// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, @@ -35,7 +35,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { Binop(mir::BinOp, Const<'tcx>, Const<'tcx>), diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 71911a5a618..7a32cfb1085 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,6 +1,7 @@ use crate::arena::Arena; use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; +use rustc_type_ir::{InferCtxtLike, OptWithInfcx}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; @@ -119,6 +120,14 @@ impl<T: fmt::Debug> fmt::Debug for List<T> { (**self).fmt(f) } } +impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + fmt::Debug::fmt(&this.map(|this| this.as_slice()), f) + } +} impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> { #[inline] @@ -202,6 +211,8 @@ unsafe impl<T: Sync> Sync for List<T> {} // We need this since `List` uses extern type `OpaqueListContents`. #[cfg(parallel_compiler)] use rustc_data_structures::sync::DynSync; + +use super::TyCtxt; #[cfg(parallel_compiler)] unsafe impl<T: DynSync> DynSync for List<T> {} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 792ee8ebb25..519bdb01623 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -53,6 +53,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use subst::*; pub use vtable::*; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7220d133f68..c82ce9112fc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,13 +11,15 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_index::{Idx, IndexVec}; use rustc_target::abi::TyAndLayout; -use rustc_type_ir::ConstKind; +use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; -use std::fmt; +use std::fmt::{self, Debug}; use std::ops::ControlFlow; use std::rc::Rc; use std::sync::Arc; +use super::{GenericArg, GenericArgKind, Region}; + impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { @@ -89,7 +91,16 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self; + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + let sig = this.data; + let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig; write!(f, "{}", unsafety.prefix_str())?; match abi { @@ -98,15 +109,15 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { }; write!(f, "fn(")?; - let inputs = self.inputs(); + let inputs = sig.inputs(); match inputs.len() { 0 if *c_variadic => write!(f, "...)")?, 0 => write!(f, ")")?, _ => { - for ty in &self.inputs()[0..(self.inputs().len() - 1)] { - write!(f, "{ty:?}, ")?; + for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] { + write!(f, "{:?}, ", &this.wrap(ty))?; } - write!(f, "{:?}", self.inputs().last().unwrap())?; + write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?; if *c_variadic { write!(f, "...")?; } @@ -114,9 +125,9 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { } } - match self.output().kind() { + match sig.output().kind() { ty::Tuple(list) if list.is_empty() => Ok(()), - _ => write!(f, " -> {:?}", self.output()), + _ => write!(f, " -> {:?}", &this.wrap(sig.output())), } } } @@ -133,6 +144,14 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { } } +impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + this.data.fmt(f) + } +} impl<'tcx> fmt::Debug for Ty<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { with_no_trimmed_paths!(fmt::Display::fmt(self, f)) @@ -217,9 +236,17 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { impl<'tcx> fmt::Debug for AliasTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { f.debug_struct("AliasTy") - .field("substs", &self.substs) - .field("def_id", &self.def_id) + .field("substs", &this.map(|data| data.substs)) + .field("def_id", &this.data.def_id) .finish() } } @@ -232,13 +259,93 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { } } } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + use ty::InferConst::*; + match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) { + None => write!(f, "{:?}", this.data), + Some(universe) => match *this.data { + Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()), + Fresh(_) => { + unreachable!() + } + }, + } + } +} + +impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data { + ty::Expr::Binop(op, lhs, rhs) => { + write!(f, "({op:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + } + ty::Expr::UnOp(op, rhs) => write!(f, "({op:?}: {:?})", &this.wrap(rhs)), + ty::Expr::FunctionCall(func, args) => { + write!(f, "{:?}(", &this.wrap(func))?; + for arg in args.as_slice().iter().rev().skip(1).rev() { + write!(f, "{:?}, ", &this.wrap(arg))?; + } + if let Some(arg) = args.last() { + write!(f, "{:?}", &this.wrap(arg))?; + } + + write!(f, ")") + } + ty::Expr::Cast(cast_kind, lhs, rhs) => { + write!(f, "({cast_kind:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + } + } + } +} + +impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("UnevaluatedConst") + .field("def", &this.data.def) + .field("substs", &this.wrap(this.data.substs)) + .finish() + } +} impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { // This reflects what `Const` looked liked before `Interned` was // introduced. We print it like this to avoid having to update expected // output in a lot of tests. - write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind()) + write!( + f, + "Const {{ ty: {:?}, kind: {:?} }}", + &this.map(|data| data.ty()), + &this.map(|data| data.kind()) + ) } } @@ -261,6 +368,66 @@ impl<T: fmt::Debug> fmt::Debug for ty::Placeholder<T> { } } +impl<'tcx> fmt::Debug for GenericArg<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.unpack() { + GenericArgKind::Lifetime(lt) => lt.fmt(f), + GenericArgKind::Type(ty) => ty.fmt(f), + GenericArgKind::Const(ct) => ct.fmt(f), + } + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data.unpack() { + GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)), + GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)), + GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)), + } + } +} + +impl<'tcx> fmt::Debug for Region<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + write!(f, "{:?}", &this.map(|data| data.kind())) + } +} + +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) { + Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()), + None => write!(f, "{:?}", this.data), + } + } +} + +impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_tuple("Binder") + .field(&this.map(|data| data.as_ref().skip_binder())) + .field(&this.data.bound_vars()) + .finish() + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2c4ff575755..9f4515b95e7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -35,9 +35,12 @@ use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::CollectAndApply; +use rustc_type_ir::ConstKind as IrConstKind; +use rustc_type_ir::DebugWithInfcx; +use rustc_type_ir::DynKind; +use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; -use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind}; -use rustc_type_ir::{DynKind, RegionKind as IrRegionKind}; use super::GenericParamDefKind; @@ -694,6 +697,15 @@ pub enum ExistentialPredicate<'tcx> { AutoTrait(DefId), } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> { + fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>( + this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + fmt::Debug::fmt(&this.data, f) + } +} + impl<'tcx> ExistentialPredicate<'tcx> { /// Compares via an ordering that will not change if modules are reordered or other changes are /// made to the tree. In particular, this ordering is preserved across incremental compilations. @@ -1571,12 +1583,6 @@ impl<'tcx> Deref for Region<'tcx> { } } -impl<'tcx> fmt::Debug for Region<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind()) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] #[derive(HashStable)] pub struct EarlyBoundRegion { diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 4d5f5b8658c..e1a58b97557 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -17,7 +17,6 @@ use smallvec::SmallVec; use core::intrinsics; use std::cmp::Ordering; -use std::fmt; use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; @@ -80,16 +79,6 @@ impl<'tcx> GenericArgKind<'tcx> { } } -impl<'tcx> fmt::Debug for GenericArg<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.fmt(f), - GenericArgKind::Type(ty) => ty.fmt(f), - GenericArgKind::Const(ct) => ct.fmt(f), - } - } -} - impl<'tcx> Ord for GenericArg<'tcx> { fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering { self.unpack().cmp(&other.unpack()) diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index a6e6de5f785..80d4e7ed02f 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,14 +4,18 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_hir = { path = "../rustc_hir" } +# Use optional dependencies for rustc_* in order to support building this crate separately. +rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } +rustc_target = { path = "../rustc_target", optional = true } tracing = "0.1" scoped-tls = "1.0" [features] default = [ + "rustc_hir", "rustc_middle", "rustc_span", + "rustc_target", ] diff --git a/compiler/rustc_smir/rust-toolchain.toml b/compiler/rustc_smir/rust-toolchain.toml index 157dfd620ee..d75e8e33b1c 100644 --- a/compiler/rustc_smir/rust-toolchain.toml +++ b/compiler/rustc_smir/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-02-28" +channel = "nightly-2023-06-14" components = [ "rustfmt", "rustc-dev" ] diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index fb03633b99b..8450bb73119 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -13,6 +13,17 @@ #![cfg_attr(not(feature = "default"), feature(rustc_private))] #![feature(local_key_cell_methods)] #![feature(ptr_metadata)] +#![feature(type_alias_impl_trait)] // Used to define opaque types. + +// Declare extern rustc_* crates to enable building this crate separately from the compiler. +#[cfg(not(feature = "default"))] +extern crate rustc_hir; +#[cfg(not(feature = "default"))] +extern crate rustc_middle; +#[cfg(not(feature = "default"))] +extern crate rustc_span; +#[cfg(not(feature = "default"))] +extern crate rustc_target; pub mod rustc_internal; pub mod stable_mir; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 609a04d263c..87e0b211556 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -3,6 +3,9 @@ //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! until stable MIR is complete. +use std::fmt::Debug; +use std::string::ToString; + use crate::{ rustc_smir::Tables, stable_mir::{self, with}, @@ -49,3 +52,10 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f); } + +/// A type that provides internal information but that can still be used for debug purpose. +pub type Opaque = impl Debug + ToString + Clone; + +pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque { + format!("{value:?}") +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 85d5bb00c4e..f22c620021e 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,11 +7,13 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. +use crate::rustc_internal::{self, opaque}; use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::stable_mir::{self, Context}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_target::abi::FieldIdx; use tracing::debug; impl<'tcx> Context for Tables<'tcx> { @@ -137,11 +139,21 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate { stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local } } -pub trait Stable { +/// Trait used to convert between an internal MIR type to a Stable MIR type. +pub(crate) trait Stable { + /// The stable representation of the type implementing Stable. type T; + /// Converts an object to the equivalent Stable MIR representation. fn stable(&self) -> Self::T; } +impl Stable for DefId { + type T = stable_mir::CrateItem; + fn stable(&self) -> Self::T { + rustc_internal::crate_item(*self) + } +} + impl<'tcx> Stable for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; fn stable(&self) -> Self::T { @@ -173,12 +185,18 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> { match self { Use(op) => stable_mir::mir::Rvalue::Use(op.stable()), Repeat(_, _) => todo!(), - Ref(_, _, _) => todo!(), - ThreadLocalRef(_) => todo!(), - AddressOf(_, _) => todo!(), - Len(_) => todo!(), + Ref(region, kind, place) => { + stable_mir::mir::Rvalue::Ref(opaque(region), kind.stable(), place.stable()) + } + ThreadLocalRef(def_id) => stable_mir::mir::Rvalue::ThreadLocalRef(def_id.stable()), + AddressOf(mutability, place) => { + stable_mir::mir::Rvalue::AddressOf(mutability.stable(), place.stable()) + } + Len(place) => stable_mir::mir::Rvalue::Len(place.stable()), Cast(_, _, _) => todo!(), - BinaryOp(_, _) => todo!(), + BinaryOp(bin_op, ops) => { + stable_mir::mir::Rvalue::BinaryOp(bin_op.stable(), ops.0.stable(), ops.1.stable()) + } CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( bin_op.stable(), ops.0.stable(), @@ -186,14 +204,119 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> { ), NullaryOp(_, _) => todo!(), UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()), - Discriminant(_) => todo!(), + Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable()), Aggregate(_, _) => todo!(), ShallowInitBox(_, _) => todo!(), - CopyForDeref(_) => todo!(), + CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable()), + } + } +} + +impl Stable for mir::Mutability { + type T = stable_mir::mir::Mutability; + fn stable(&self) -> Self::T { + use mir::Mutability::*; + match *self { + Not => stable_mir::mir::Mutability::Not, + Mut => stable_mir::mir::Mutability::Mut, + } + } +} + +impl Stable for mir::BorrowKind { + type T = stable_mir::mir::BorrowKind; + fn stable(&self) -> Self::T { + use mir::BorrowKind::*; + match *self { + Shared => stable_mir::mir::BorrowKind::Shared, + Shallow => stable_mir::mir::BorrowKind::Shallow, + Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable() }, + } + } +} + +impl Stable for mir::MutBorrowKind { + type T = stable_mir::mir::MutBorrowKind; + fn stable(&self) -> Self::T { + use mir::MutBorrowKind::*; + match *self { + Default => stable_mir::mir::MutBorrowKind::Default, + TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow, + ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture, + } + } +} + +impl<'tcx> Stable for mir::NullOp<'tcx> { + type T = stable_mir::mir::NullOp; + fn stable(&self) -> Self::T { + use mir::NullOp::*; + match self { + SizeOf => stable_mir::mir::NullOp::SizeOf, + AlignOf => stable_mir::mir::NullOp::AlignOf, + OffsetOf(indices) => { + stable_mir::mir::NullOp::OffsetOf(indices.iter().map(|idx| idx.stable()).collect()) + } + } + } +} + +impl Stable for mir::CastKind { + type T = stable_mir::mir::CastKind; + fn stable(&self) -> Self::T { + use mir::CastKind::*; + match self { + PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress, + PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress, + PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable()), + DynStar => stable_mir::mir::CastKind::DynStar, + IntToInt => stable_mir::mir::CastKind::IntToInt, + FloatToInt => stable_mir::mir::CastKind::FloatToInt, + FloatToFloat => stable_mir::mir::CastKind::FloatToFloat, + IntToFloat => stable_mir::mir::CastKind::IntToFloat, + PtrToPtr => stable_mir::mir::CastKind::PtrToPtr, + FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr, + Transmute => stable_mir::mir::CastKind::Transmute, } } } +impl Stable for ty::adjustment::PointerCoercion { + type T = stable_mir::mir::PointerCoercion; + fn stable(&self) -> Self::T { + use ty::adjustment::PointerCoercion; + match self { + PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer, + PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer, + PointerCoercion::ClosureFnPointer(unsafety) => { + stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable()) + } + PointerCoercion::MutToConstPointer => { + stable_mir::mir::PointerCoercion::MutToConstPointer + } + PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer, + PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize, + } + } +} + +impl Stable for rustc_hir::Unsafety { + type T = stable_mir::mir::Safety; + fn stable(&self) -> Self::T { + match self { + rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe, + rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal, + } + } +} + +impl Stable for FieldIdx { + type T = usize; + fn stable(&self) -> Self::T { + self.as_usize() + } +} + impl<'tcx> Stable for mir::Operand<'tcx> { type T = stable_mir::mir::Operand; fn stable(&self) -> Self::T { @@ -229,34 +352,38 @@ impl Stable for mir::UnwindAction { } } -fn rustc_assert_msg_to_msg<'tcx>( - assert_message: &rustc_middle::mir::AssertMessage<'tcx>, -) -> stable_mir::mir::AssertMessage { - use rustc_middle::mir::AssertKind; - match assert_message { - AssertKind::BoundsCheck { len, index } => { - stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() } - } - AssertKind::Overflow(bin_op, op1, op2) => { - stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable()) - } - AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), - AssertKind::DivisionByZero(op) => { - stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) - } - AssertKind::RemainderByZero(op) => { - stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) - } - AssertKind::ResumedAfterReturn(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) - } - AssertKind::ResumedAfterPanic(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) - } - AssertKind::MisalignedPointerDereference { required, found } => { - stable_mir::mir::AssertMessage::MisalignedPointerDereference { - required: required.stable(), - found: found.stable(), +impl<'tcx> Stable for mir::AssertMessage<'tcx> { + type T = stable_mir::mir::AssertMessage; + fn stable(&self) -> Self::T { + use rustc_middle::mir::AssertKind; + match self { + AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { + len: len.stable(), + index: index.stable(), + }, + AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( + bin_op.stable(), + op1.stable(), + op2.stable(), + ), + AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), + AssertKind::DivisionByZero(op) => { + stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) + } + AssertKind::RemainderByZero(op) => { + stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) + } + AssertKind::ResumedAfterReturn(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) + } + AssertKind::ResumedAfterPanic(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) + } + AssertKind::MisalignedPointerDereference { required, found } => { + stable_mir::mir::AssertMessage::MisalignedPointerDereference { + required: required.stable(), + found: found.stable(), + } } } } @@ -381,7 +508,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> { Assert { cond, expected, msg, target, unwind } => Terminator::Assert { cond: cond.stable(), expected: *expected, - msg: rustc_assert_msg_to_msg(msg), + msg: msg.stable(), target: target.as_usize(), unwind: unwind.stable(), }, diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 468e915d1a0..fa3b0d6c559 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -1,4 +1,5 @@ -use crate::stable_mir::ty::Ty; +use crate::rustc_internal::Opaque; +use crate::stable_mir::{self, ty::Ty}; #[derive(Clone, Debug)] pub struct Body { @@ -136,12 +137,98 @@ pub enum Statement { Nop, } +type Region = Opaque; + // FIXME this is incomplete #[derive(Clone, Debug)] pub enum Rvalue { - Use(Operand), + /// Creates a pointer with the indicated mutability to the place. + /// + /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like + /// `&raw v` or `addr_of!(v)`. + AddressOf(Mutability, Place), + + /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second + /// parameter may be a `usize` as well. + /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + /// matching, up to the usual caveat of the lifetimes in function pointers. + /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + /// truncated as needed. + /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + /// types and return a value of that type. + /// * The remaining operations accept signed integers, unsigned integers, or floats with + /// matching types and return a value of that type. + BinaryOp(BinOp, Operand, Operand), + + /// Performs essentially all of the casts that can be performed via `as`. + /// + /// This allows for casts from/to a variety of types. + Cast(CastKind, Operand, Ty), + + /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. + /// + /// For addition, subtraction, and multiplication on integers the error condition is set when + /// the infinite precision result would not be equal to the actual result. CheckedBinaryOp(BinOp, Operand, Operand), + + /// A CopyForDeref is equivalent to a read from a place. + /// When such a read happens, it is guaranteed that the only use of the returned value is a + /// deref operation, immediately followed by one or more projections. + CopyForDeref(Place), + + /// Computes the discriminant of the place, returning it as an integer of type + /// [`discriminant_ty`]. Returns zero for types without discriminant. + /// + /// The validity requirements for the underlying value are undecided for this rvalue, see + /// [#91095]. Note too that the value of the discriminant is not the same thing as the + /// variant index; use [`discriminant_for_variant`] to convert. + /// + /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty + /// [#91095]: https://github.com/rust-lang/rust/issues/91095 + /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant + Discriminant(Place), + + /// Yields the length of the place, as a `usize`. + /// + /// If the type of the place is an array, this is the array length. For slices (`[T]`, not + /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is + /// ill-formed for places of other types. + Len(Place), + + /// Creates a reference to the place. + Ref(Region, BorrowKind, Place), + + /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. + /// + /// This is different from a normal transmute because dataflow analysis will treat the box as + /// initialized but its content as uninitialized. Like other pointer casts, this in general + /// affects alias analysis. + ShallowInitBox(Operand, Ty), + + /// Creates a pointer/reference to the given thread local. + /// + /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a + /// `*const T`, and if neither of those apply a `&T`. + /// + /// **Note:** This is a runtime operation that actually executes code and is in this sense more + /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to + /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. + /// + /// **Needs clarification**: Are there weird additional semantics here related to the runtime + /// nature of this operation? + ThreadLocalRef(stable_mir::CrateItem), + + /// Exactly like `BinaryOp`, but less operands. + /// + /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; + /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds + /// return a value with the same type as their operand. UnaryOp(UnOp, Operand), + + /// Yields the operand unchanged + Use(Operand), } #[derive(Clone, Debug)] @@ -157,8 +244,98 @@ pub struct Place { pub projection: String, } +type FieldIdx = usize; + #[derive(Clone, Debug)] pub struct SwitchTarget { pub value: u128, pub target: usize, } + +#[derive(Clone, Debug)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, + + /// Data is mutable and not aliasable. + Mut { + /// `true` if this borrow arose from method-call auto-ref + kind: MutBorrowKind, + }, +} + +#[derive(Clone, Debug)] +pub enum MutBorrowKind { + Default, + TwoPhaseBorrow, + ClosureCapture, +} + +#[derive(Clone, Debug)] +pub enum Mutability { + Not, + Mut, +} + +#[derive(Clone, Debug)] +pub enum Safety { + Unsafe, + Normal, +} + +#[derive(Clone, Debug)] +pub enum PointerCoercion { + /// Go from a fn-item type to a fn-pointer type. + ReifyFnPointer, + + /// Go from a safe fn pointer to an unsafe fn pointer. + UnsafeFnPointer, + + /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. + /// It cannot convert a closure that requires unsafe. + ClosureFnPointer(Safety), + + /// Go from a mut raw pointer to a const raw pointer. + MutToConstPointer, + + /// Go from `*const [T; N]` to `*const T` + ArrayToPointer, + + /// Unsize a pointer/reference value, e.g., `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + /// This will do things like convert thin pointers to fat + /// pointers, or convert structs containing thin pointers to + /// structs containing fat pointers, or convert between fat + /// pointers. + Unsize, +} + +#[derive(Clone, Debug)] +pub enum CastKind { + PointerExposeAddress, + PointerFromExposedAddress, + PointerCoercion(PointerCoercion), + DynStar, + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, +} + +#[derive(Clone, Debug)] +pub enum NullOp { + /// Returns the size of a value of that type. + SizeOf, + /// Returns the minimum alignment of a type. + AlignOf, + /// Returns the offset of a field. + OffsetOf(Vec<FieldIdx>), +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f342180590f..4dc06d2bfac 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1640,6 +1640,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) .into(), }; + // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice + // to deeply normalize this type. let normalized_term = ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 878a6b784ed..9ca26d18ae1 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -31,6 +31,7 @@ mod macros; mod structural_impls; pub use codec::*; +pub use structural_impls::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use sty::*; pub use ty_info::*; @@ -39,41 +40,41 @@ pub trait HashStableContext {} pub trait Interner: Sized { type AdtDef: Clone + Debug + Hash + Ord; - type SubstsRef: Clone + Debug + Hash + Ord; + type SubstsRef: Clone + DebugWithInfcx<Self> + Hash + Ord; type DefId: Clone + Debug + Hash + Ord; type Binder<T>; - type Ty: Clone + Debug + Hash + Ord; - type Const: Clone + Debug + Hash + Ord; - type Region: Clone + Debug + Hash + Ord; + type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Const: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Region: Clone + DebugWithInfcx<Self> + Hash + Ord; type Predicate; type TypeAndMut: Clone + Debug + Hash + Ord; type Mutability: Clone + Debug + Hash + Ord; type Movability: Clone + Debug + Hash + Ord; - type PolyFnSig: Clone + Debug + Hash + Ord; - type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord; - type BinderListTy: Clone + Debug + Hash + Ord; + type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord; + type ListBinderExistentialPredicate: Clone + DebugWithInfcx<Self> + Hash + Ord; + type BinderListTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ListTy: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; - type AliasTy: Clone + Debug + Hash + Ord; + type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; type PlaceholderType: Clone + Debug + Hash + Ord; + type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ErrorGuaranteed: Clone + Debug + Hash + Ord; type PredicateKind: Clone + Debug + Hash + PartialEq + Eq; type AllocId: Clone + Debug + Hash + Ord; - type InferConst: Clone + Debug + Hash + Ord; - type AliasConst: Clone + Debug + Hash + Ord; + type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord; + type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderConst: Clone + Debug + Hash + Ord; type ParamConst: Clone + Debug + Hash + Ord; type BoundConst: Clone + Debug + Hash + Ord; - type InferTy: Clone + Debug + Hash + Ord; type ValueConst: Clone + Debug + Hash + Ord; - type ExprConst: Clone + Debug + Hash + Ord; + type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord; type EarlyBoundRegion: Clone + Debug + Hash + Ord; type BoundRegion: Clone + Debug + Hash + Ord; type FreeRegion: Clone + Debug + Hash + Ord; - type RegionVid: Clone + Debug + Hash + Ord; + type RegionVid: Clone + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability); @@ -775,20 +776,6 @@ impl fmt::Debug for FloatVid { } } -impl fmt::Debug for InferTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InferTy::*; - match *self { - TyVar(ref v) => v.fmt(f), - IntVar(ref v) => v.fmt(f), - FloatVar(ref v) => v.fmt(f), - FreshTy(v) => write!(f, "FreshTy({v:?})"), - FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"), - FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"), - } - } -} - impl fmt::Debug for Variance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 1e42175f6e3..1a2d6d64eb0 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -4,12 +4,13 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy}; +use crate::{ConstKind, FloatTy, InferTy, IntTy, Interner, UintTy, UniverseIndex}; use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use core::fmt; +use std::marker::PhantomData; use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// @@ -165,6 +166,116 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix } } +/////////////////////////////////////////////////// +// Debug impls + +pub trait InferCtxtLike<I: Interner> { + fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>; + fn universe_of_lt(&self, lt: I::RegionVid) -> Option<UniverseIndex>; + fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>; +} + +impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible { + fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> { + match *self {} + } + fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> { + match *self {} + } + fn universe_of_lt(&self, _lt: <I as Interner>::RegionVid) -> Option<UniverseIndex> { + match *self {} + } +} + +pub trait DebugWithInfcx<I: Interner>: fmt::Debug { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result; +} + +impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f) + } +} +impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + match f.alternate() { + true => { + write!(f, "[\n")?; + for element in this.data.iter() { + write!(f, "{:?},\n", &this.wrap(element))?; + } + write!(f, "]") + } + false => { + write!(f, "[")?; + if this.data.len() > 0 { + for element in &this.data[..(this.data.len() - 1)] { + write!(f, "{:?}, ", &this.wrap(element))?; + } + if let Some(element) = this.data.last() { + write!(f, "{:?}", &this.wrap(element))?; + } + } + write!(f, "]") + } + } + } +} + +pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> { + pub data: T, + pub infcx: Option<&'a InfCtx>, + _interner: PhantomData<I>, +} + +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {} +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> { + fn clone(&self) -> Self { + Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner } + } +} + +impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> { + pub fn new_no_ctx(data: T) -> Self { + Self { data, infcx: None, _interner: PhantomData } + } +} + +impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> { + pub fn new(data: T, infcx: &'a InfCtx) -> Self { + Self { data, infcx: Some(infcx), _interner: PhantomData } + } + + pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> { + OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData } + } + + pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> { + OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData } + } + + pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> { + OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData } + } +} + +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug + for OptWithInfcx<'_, I, InfCtx, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugWithInfcx::fmt(self.as_ref(), f) + } +} + impl fmt::Debug for IntTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name_str()) @@ -183,20 +294,60 @@ impl fmt::Debug for FloatTy { } } +impl fmt::Debug for InferTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InferTy::*; + match *self { + TyVar(ref v) => v.fmt(f), + IntVar(ref v) => v.fmt(f), + FloatVar(ref v) => v.fmt(f), + FreshTy(v) => write!(f, "FreshTy({v:?})"), + FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"), + FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"), + } + } +} +impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + use InferTy::*; + match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) { + None => write!(f, "{:?}", this.data), + Some(universe) => match *this.data { + TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()), + IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => { + unreachable!() + } + }, + } + } +} + impl<I: Interner> fmt::Debug for ConstKind<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { use ConstKind::*; - match self { + + match this.data { Param(param) => write!(f, "{param:?}"), - Infer(var) => write!(f, "{var:?}"), + Infer(var) => write!(f, "{:?}", &this.wrap(var)), Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()), Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => { - write!(f, "{uv:?}") + write!(f, "{:?}", &this.wrap(uv)) } Value(valtree) => write!(f, "{valtree:?}"), Error(_) => write!(f, "{{const error}}"), - Expr(expr) => write!(f, "{expr:?}"), + Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), } } } diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index b696f9b9b59..416e8a3d2d2 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -3,7 +3,6 @@ use std::cmp::Ordering; use std::{fmt, hash}; -use crate::DebruijnIndex; use crate::FloatTy; use crate::HashStableContext; use crate::IntTy; @@ -11,6 +10,7 @@ use crate::Interner; use crate::TyDecoder; use crate::TyEncoder; use crate::UintTy; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; use self::RegionKind::*; use self::TyKind::*; @@ -503,42 +503,48 @@ impl<I: Interner> hash::Hash for TyKind<I> { } } -// This is manually implemented because a derive would require `I: Debug` -impl<I: Interner> fmt::Debug for TyKind<I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { +impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> fmt::Result { + match this.data { Bool => write!(f, "bool"), Char => write!(f, "char"), Int(i) => write!(f, "{i:?}"), Uint(u) => write!(f, "{u:?}"), Float(float) => write!(f, "{float:?}"), - Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s), + Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, &this.wrap(s)), Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), Str => write!(f, "str"), - Array(t, c) => write!(f, "[{t:?}; {c:?}]"), - Slice(t) => write!(f, "[{t:?}]"), + Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), + Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), RawPtr(p) => { let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone()); match I::mutability_is_mut(mutbl) { true => write!(f, "*mut "), false => write!(f, "*const "), }?; - write!(f, "{ty:?}") + write!(f, "{:?}", &this.wrap(ty)) } Ref(r, t, m) => match I::mutability_is_mut(m.clone()) { - true => write!(f, "&{r:?} mut {t:?}"), - false => write!(f, "&{r:?} {t:?}"), + true => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)), + false => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)), }, - FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s), - FnPtr(s) => write!(f, "{s:?}"), + FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, &this.wrap(s)), + FnPtr(s) => write!(f, "{:?}", &this.wrap(s)), Dynamic(p, r, repr) => match repr { - DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"), - DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"), + DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)), + DynKind::DynStar => { + write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r)) + } }, - Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), - Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), - GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), - GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), + Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)), + Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, &this.wrap(s), m), + GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", &this.wrap(g)), + GeneratorWitnessMIR(d, s) => { + f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, &this.wrap(s)) + } Never => write!(f, "!"), Tuple(t) => { let mut iter = t.clone().into_iter(); @@ -547,28 +553,34 @@ impl<I: Interner> fmt::Debug for TyKind<I> { match iter.next() { None => return write!(f, ")"), - Some(ty) => write!(f, "{ty:?}")?, + Some(ty) => write!(f, "{:?}", &this.wrap(ty))?, }; match iter.next() { None => return write!(f, ",)"), - Some(ty) => write!(f, "{ty:?})")?, + Some(ty) => write!(f, "{:?})", &this.wrap(ty))?, } for ty in iter { - write!(f, ", {ty:?}")?; + write!(f, ", {:?}", &this.wrap(ty))?; } write!(f, ")") } - Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), + Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, &this.wrap(a)), Param(p) => write!(f, "{p:?}"), Bound(d, b) => crate::debug_bound_var(f, *d, b), Placeholder(p) => write!(f, "{p:?}"), - Infer(t) => write!(f, "{t:?}"), + Infer(t) => write!(f, "{:?}", this.wrap(t)), TyKind::Error(_) => write!(f, "{{type error}}"), } } } +// This is manually implemented because a derive would require `I: Debug` +impl<I: Interner> fmt::Debug for TyKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} // This is manually implemented because a derive would require `I: Encodable` impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I> @@ -1356,21 +1368,23 @@ impl<I: Interner> hash::Hash for RegionKind<I> { } } -// This is manually implemented because a derive would require `I: Debug` -impl<I: Interner> fmt::Debug for RegionKind<I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { +impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data { ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"), ReLateBound(binder_id, bound_region) => { write!(f, "ReLateBound({binder_id:?}, {bound_region:?})") } - ReFree(fr) => fr.fmt(f), + ReFree(fr) => write!(f, "{fr:?}"), ReStatic => f.write_str("ReStatic"), - ReVar(vid) => vid.fmt(f), + ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)), RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"), @@ -1380,6 +1394,11 @@ impl<I: Interner> fmt::Debug for RegionKind<I> { } } } +impl<I: Interner> fmt::Debug for RegionKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} // This is manually implemented because a derive would require `I: Encodable` impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I> diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs index 4800eeda022..1f3f80b9618 100644 --- a/library/std/src/io/readbuf.rs +++ b/library/std/src/io/readbuf.rs @@ -99,6 +99,13 @@ impl<'data> BorrowedBuf<'data> { unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) } } + /// Returns a mutable reference to the filled portion of the buffer. + #[inline] + pub fn filled_mut(&mut self) -> &mut [u8] { + // SAFETY: We only slice the filled part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) } + } + /// Returns a cursor over the unfilled part of the buffer. #[inline] pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index efe621bdb7d..caa7417011e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -688,8 +688,8 @@ fn cp_rustc_component_to_ci_sysroot( contents: Vec<String>, ) { let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + let ci_rustc_dir = builder.config.ci_rustc_dir(); - let ci_rustc_dir = builder.out.join(&*builder.build.build.triple).join("ci-rustc"); for file in contents { let src = ci_rustc_dir.join(&file); let dst = sysroot.join(file); @@ -1424,7 +1424,7 @@ impl Step for Sysroot { // FIXME: this is wrong when compiler.host != build, but we don't support that today OsStr::new(std::env::consts::DLL_EXTENSION), ]; - let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build); + let ci_rustc_dir = builder.config.ci_rustc_dir(); builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| { if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) { return true; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 28ae46efefe..34853743323 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1375,6 +1375,25 @@ impl Config { let mut omit_git_hash = None; if let Some(rust) = toml.rust { + set(&mut config.channel, rust.channel); + + config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc); + // This list is incomplete, please help by expanding it! + if config.download_rustc_commit.is_some() { + // We need the channel used by the downloaded compiler to match the one we set for rustdoc; + // otherwise rustdoc-ui tests break. + let ci_channel = t!(fs::read_to_string(config.src.join("src/ci/channel"))); + let ci_channel = ci_channel.trim_end(); + if config.channel != ci_channel + && !(config.channel == "dev" && ci_channel == "nightly") + { + panic!( + "setting rust.channel={} is incompatible with download-rustc", + config.channel + ); + } + } + debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; @@ -1386,6 +1405,7 @@ impl Config { debuginfo_level_std = rust.debuginfo_level_std; debuginfo_level_tools = rust.debuginfo_level_tools; debuginfo_level_tests = rust.debuginfo_level_tests; + config.rust_split_debuginfo = rust .split_debuginfo .as_deref() @@ -1401,7 +1421,6 @@ impl Config { set(&mut config.jemalloc, rust.jemalloc); set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.backtrace, rust.backtrace); - set(&mut config.channel, rust.channel); config.description = rust.description; set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.verbose_tests, rust.verbose_tests); @@ -1442,8 +1461,6 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc); - config.rust_lto = rust .lto .as_deref() @@ -1555,6 +1572,11 @@ impl Config { let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { + if config.download_rustc_commit.is_some() && triple == &*config.build.triple { + panic!( + "setting llvm_config for the host is incompatible with download-rustc" + ); + } target.llvm_config = Some(config.src.join(s)); } target.llvm_has_rust_patches = cfg.llvm_has_rust_patches; @@ -1825,6 +1847,12 @@ impl Config { self.out.join(&*self.build.triple).join("ci-llvm") } + /// Directory where the extracted `rustc-dev` component is stored. + pub(crate) fn ci_rustc_dir(&self) -> PathBuf { + assert!(self.download_rustc()); + self.out.join(self.build.triple).join("ci-rustc") + } + /// Determine whether llvm should be linked dynamically. /// /// If `false`, llvm should be linked statically. @@ -1860,11 +1888,11 @@ impl Config { self.download_rustc_commit().is_some() } - pub(crate) fn download_rustc_commit(&self) -> Option<&'static str> { + pub(crate) fn download_rustc_commit(&self) -> Option<&str> { static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new(); if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() { // avoid trying to actually download the commit - return None; + return self.download_rustc_commit.as_deref(); } DOWNLOAD_RUSTC diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index cb40521dda7..a081f6189d7 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -402,7 +402,11 @@ impl Config { fn ci_component_contents(&self, stamp_file: &str) -> Vec<String> { assert!(self.download_rustc()); - let ci_rustc_dir = self.out.join(&*self.build.triple).join("ci-rustc"); + if self.dry_run() { + return vec![]; + } + + let ci_rustc_dir = self.ci_rustc_dir(); let stamp_file = ci_rustc_dir.join(stamp_file); let contents_file = t!(File::open(&stamp_file), stamp_file.display().to_string()); t!(BufReader::new(contents_file).lines().collect()) @@ -419,7 +423,7 @@ impl Config { self.download_toolchain( &version, "ci-rustc", - commit, + &format!("{commit}-{}", self.llvm_assertions), &extra_components, Self::download_ci_component, ); @@ -495,8 +499,15 @@ impl Config { /// Download a single component of a CI-built toolchain (not necessarily a published nightly). // NOTE: intentionally takes an owned string to avoid downloading multiple times by accident - fn download_ci_component(&self, filename: String, prefix: &str, commit: &str) { - Self::download_component(self, DownloadSource::CI, filename, prefix, commit, "ci-rustc") + fn download_ci_component(&self, filename: String, prefix: &str, commit_with_assertions: &str) { + Self::download_component( + self, + DownloadSource::CI, + filename, + prefix, + commit_with_assertions, + "ci-rustc", + ) } fn download_component( @@ -516,11 +527,18 @@ impl Config { let bin_root = self.out.join(self.build.triple).join(destination); let tarball = cache_dir.join(&filename); let (base_url, url, should_verify) = match mode { - DownloadSource::CI => ( - self.stage0_metadata.config.artifacts_server.clone(), - format!("{key}/{filename}"), - false, - ), + DownloadSource::CI => { + let dist_server = if self.llvm_assertions { + self.stage0_metadata.config.artifacts_with_llvm_assertions_server.clone() + } else { + self.stage0_metadata.config.artifacts_server.clone() + }; + let url = format!( + "{}/{filename}", + key.strip_suffix(&format!("-{}", self.llvm_assertions)).unwrap() + ); + (dist_server, url, false) + } DownloadSource::Dist => { let dist_server = env::var("RUSTUP_DIST_SERVER") .unwrap_or(self.stage0_metadata.config.dist_server.to_string()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0a7aff62257..0b509132043 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -822,11 +822,6 @@ impl Build { self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir()) } - /// Directory where the extracted `rustc-dev` component is stored. - fn ci_rustc_dir(&self, target: TargetSelection) -> PathBuf { - self.out.join(&*target.triple).join("ci-rustc") - } - /// Root output directory for LLVM compiled for `target` /// /// Note that if LLVM is configured externally then the directory returned diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 0907291b54d..a34465ebffb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2348,7 +2348,7 @@ impl Step for Crate { // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. // Override it. - if builder.download_rustc() { + if builder.download_rustc() && compiler.stage > 0 { let sysroot = builder .out .join(compiler.host.triple) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 40183063869..41a9eb82cb5 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -451,12 +451,11 @@ foo( #### Multi-line elements -If any element in a chain is formatted across multiple lines, then that element -and any later elements must be on their own line. Earlier elements may be kept -on a single line. E.g., +If any element in a chain is formatted across multiple lines, put that element +and any later elements on their own lines. ```rust -a.b.c()?.d +a.b.c()? .foo( an_expr, another_expr, diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index b11fb287cf4..5be8ef7996b 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -39,7 +39,6 @@ impl<'a> LintExtractor<'a> { fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> { let mut result = BTreeMap::new(); let mut cmd = Command::new(self.rustc_path); - cmd.env_remove("LD_LIBRARY_PATH"); cmd.arg("-Whelp"); let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index fe29b9abda3..b7c8b9ed2e3 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -403,12 +403,6 @@ impl<'a> LintExtractor<'a> { fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; let mut cmd = Command::new(self.rustc_path); - // NOTE: bootstrap sets `LD_LIBRARY_PATH` for building lint-docs itself. - // Unfortunately, lint-docs is a bootstrap tool while rustc is built from source, - // and sometimes the paths conflict. In particular, when using `download-rustc`, - // the LLVM versions can differ between `ci-llvm` and `ci-rustc-sysroot`. - // Unset LD_LIBRARY_PATH here so it doesn't interfere with running the compiler. - cmd.env_remove("LD_LIBRARY_PATH"); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.rs b/tests/ui-fulldeps/missing-rustc-driver-error.rs index 654cd6f6dc9..b627a207c98 100644 --- a/tests/ui-fulldeps/missing-rustc-driver-error.rs +++ b/tests/ui-fulldeps/missing-rustc-driver-error.rs @@ -1,8 +1,8 @@ // Test that we get the following hint when trying to use a compiler crate without rustc_driver. // error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate // compile-flags: --emit link -// The exactly list of required crates depends on the target. as such only test Unix targets. -// only-unix +// normalize-stderr-test ".*crate .* required.*\n\n" -> "" +// normalize-stderr-test: "aborting due to [0-9]+" -> "aborting due to NUMBER" #![feature(rustc_private)] diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.stderr b/tests/ui-fulldeps/missing-rustc-driver-error.stderr index 939e888e5cb..d7bf27d6349 100644 --- a/tests/ui-fulldeps/missing-rustc-driver-error.stderr +++ b/tests/ui-fulldeps/missing-rustc-driver-error.stderr @@ -2,15 +2,5 @@ error: crate `rustc_serialize` required to be available in rlib format, but was | = help: try adding `extern crate rustc_driver;` at the top level of this crate -error: crate `smallvec` required to be available in rlib format, but was not found in this form - -error: crate `thin_vec` required to be available in rlib format, but was not found in this form - -error: crate `indexmap` required to be available in rlib format, but was not found in this form - -error: crate `hashbrown` required to be available in rlib format, but was not found in this form - -error: crate `equivalent` required to be available in rlib format, but was not found in this form - -error: aborting due to 6 previous errors +error: aborting due to NUMBER previous errors diff --git a/tests/ui/inference/issue-113354.fixed b/tests/ui/inference/issue-113354.fixed new file mode 100644 index 00000000000..804db985ae1 --- /dev/null +++ b/tests/ui/inference/issue-113354.fixed @@ -0,0 +1,4 @@ +//run-rustfix +fn main() { + let _ = || { while let Some(_) = Some(1) { } }; //~ ERROR mismatched types +} diff --git a/tests/ui/inference/issue-113354.rs b/tests/ui/inference/issue-113354.rs new file mode 100644 index 00000000000..ec33d1f8b84 --- /dev/null +++ b/tests/ui/inference/issue-113354.rs @@ -0,0 +1,4 @@ +//run-rustfix +fn main() { + let _ = || { while Some(_) = Some(1) { } }; //~ ERROR mismatched types +} diff --git a/tests/ui/inference/issue-113354.stderr b/tests/ui/inference/issue-113354.stderr new file mode 100644 index 00000000000..045a5aa7bf0 --- /dev/null +++ b/tests/ui/inference/issue-113354.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-113354.rs:3:24 + | +LL | let _ = || { while Some(_) = Some(1) { } }; + | ^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: consider adding `let` + | +LL | let _ = || { while let Some(_) = Some(1) { } }; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs new file mode 100644 index 00000000000..5a893f2d8ad --- /dev/null +++ b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs @@ -0,0 +1,12 @@ +trait T {} + +struct S {} + +impl S { + fn owo(&self, _: Option<&impl T>) {} +} + +fn main() { + (S {}).owo(None) + //~^ ERROR type annotations needed +} diff --git a/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr new file mode 100644 index 00000000000..0ec219415ab --- /dev/null +++ b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/issue-113264-incorrect-impl-trait-in-path-suggestion.rs:10:16 + | +LL | (S {}).owo(None) + | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` + | +help: consider specifying the generic argument + | +LL | (S {}).owo(None::<&_>) + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/panics/abort-on-panic.rs b/tests/ui/panics/abort-on-panic.rs index 1f6ad64c071..7fbee85ffd1 100644 --- a/tests/ui/panics/abort-on-panic.rs +++ b/tests/ui/panics/abort-on-panic.rs @@ -1,4 +1,6 @@ // run-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next #![allow(unused_must_use)] #![feature(c_unwind)] diff --git a/tests/ui/sanitize/address.rs b/tests/ui/sanitize/address.rs index 5b2cea87560..1faab1fd2fc 100644 --- a/tests/ui/sanitize/address.rs +++ b/tests/ui/sanitize/address.rs @@ -1,11 +1,12 @@ // needs-sanitizer-support // needs-sanitizer-address +// ignore-cross-compile // // compile-flags: -Z sanitizer=address -O -g // // run-fail // error-pattern: AddressSanitizer: stack-buffer-overflow -// error-pattern: 'xs' (line 13) <== Memory access at offset +// error-pattern: 'xs' (line 14) <== Memory access at offset use std::hint::black_box; diff --git a/tests/ui/sanitize/badfree.rs b/tests/ui/sanitize/badfree.rs index 095a6f4697b..c8d1ce7dff2 100644 --- a/tests/ui/sanitize/badfree.rs +++ b/tests/ui/sanitize/badfree.rs @@ -1,5 +1,6 @@ // needs-sanitizer-support // needs-sanitizer-address +// ignore-cross-compile // // compile-flags: -Z sanitizer=address -O // diff --git a/tests/ui/sanitize/issue-72154-lifetime-markers.rs b/tests/ui/sanitize/issue-72154-lifetime-markers.rs index b2e182238ce..3d9c51daa65 100644 --- a/tests/ui/sanitize/issue-72154-lifetime-markers.rs +++ b/tests/ui/sanitize/issue-72154-lifetime-markers.rs @@ -5,6 +5,7 @@ // // needs-sanitizer-support // needs-sanitizer-address +// ignore-cross-compile // // compile-flags: -Copt-level=0 -Zsanitizer=address // run-pass diff --git a/tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs index 33e18e35522..052a40598a8 100644 --- a/tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs +++ b/tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -4,6 +4,7 @@ // // needs-sanitizer-support // needs-sanitizer-address +// ignore-cross-compile // // no-prefer-dynamic // revisions: opt0 opt1 diff --git a/tests/ui/sanitize/use-after-scope.rs b/tests/ui/sanitize/use-after-scope.rs index 30be2ae6f09..de63eea194b 100644 --- a/tests/ui/sanitize/use-after-scope.rs +++ b/tests/ui/sanitize/use-after-scope.rs @@ -1,5 +1,6 @@ // needs-sanitizer-support // needs-sanitizer-address +// ignore-cross-compile // // compile-flags: -Zsanitizer=address // run-fail diff --git a/tests/ui/parser/type-alias-where-fixable.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed index 2f47c0d91fa..2f47c0d91fa 100644 --- a/tests/ui/parser/type-alias-where-fixable.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed diff --git a/tests/ui/parser/type-alias-where-fixable.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs index b20aa9398b5..b20aa9398b5 100644 --- a/tests/ui/parser/type-alias-where-fixable.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs diff --git a/tests/ui/parser/type-alias-where-fixable.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr index f0acb388b97..b4de051845f 100644 --- a/tests/ui/parser/type-alias-where-fixable.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:13:16 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:13:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:16:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:16:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:24:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:24:17 | LL | type Assoc2 where u32: Copy, i32: Copy = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed new file mode 100644 index 00000000000..d171eba50b7 --- /dev/null +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed @@ -0,0 +1,15 @@ +// check-pass +// run-rustfix + +#![feature(associated_type_defaults)] + +trait Trait { + // Not fine, suggests moving. + type Assoc = () where u32: Copy; + //~^ WARNING where clause not allowed here + // Not fine, suggests moving `u32: Copy` + type Assoc2 = () where i32: Copy, u32: Copy; + //~^ WARNING where clause not allowed here +} + +fn main() {} diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs new file mode 100644 index 00000000000..59afee65794 --- /dev/null +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs @@ -0,0 +1,15 @@ +// check-pass +// run-rustfix + +#![feature(associated_type_defaults)] + +trait Trait { + // Not fine, suggests moving. + type Assoc where u32: Copy = (); + //~^ WARNING where clause not allowed here + // Not fine, suggests moving `u32: Copy` + type Assoc2 where u32: Copy = () where i32: Copy; + //~^ WARNING where clause not allowed here +} + +fn main() {} diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr new file mode 100644 index 00000000000..a81cb8c8cd6 --- /dev/null +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr @@ -0,0 +1,29 @@ +warning: where clause not allowed here + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:8:16 + | +LL | type Assoc where u32: Copy = (); + | ^^^^^^^^^^^^^^^ + | + = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information + = note: `#[warn(deprecated_where_clause_location)]` on by default +help: move it to the end of the type declaration + | +LL - type Assoc where u32: Copy = (); +LL + type Assoc = () where u32: Copy; + | + +warning: where clause not allowed here + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:11:17 + | +LL | type Assoc2 where u32: Copy = () where i32: Copy; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information +help: move it to the end of the type declaration + | +LL - type Assoc2 where u32: Copy = () where i32: Copy; +LL + type Assoc2 = () where i32: Copy, u32: Copy; + | + +warning: 2 warnings emitted + diff --git a/tests/ui/parser/type-alias-where.rs b/tests/ui/where-clauses/where-clause-placement-type-alias.rs index 62e301cb408..62e301cb408 100644 --- a/tests/ui/parser/type-alias-where.rs +++ b/tests/ui/where-clauses/where-clause-placement-type-alias.rs diff --git a/tests/ui/parser/type-alias-where.stderr b/tests/ui/where-clauses/where-clause-placement-type-alias.stderr index fb838179266..b3c155a48dd 100644 --- a/tests/ui/parser/type-alias-where.stderr +++ b/tests/ui/where-clauses/where-clause-placement-type-alias.stderr @@ -1,5 +1,5 @@ error: where clauses are not allowed after the type for type aliases - --> $DIR/type-alias-where.rs:6:15 + --> $DIR/where-clause-placement-type-alias.rs:6:15 | LL | type Bar = () where u32: Copy; | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | type Bar = () where u32: Copy; = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information error: where clauses are not allowed after the type for type aliases - --> $DIR/type-alias-where.rs:8:15 + --> $DIR/where-clause-placement-type-alias.rs:8:15 | LL | type Baz = () where; | ^^^^^ |
