diff options
Diffstat (limited to 'src')
61 files changed, 1230 insertions, 816 deletions
diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 23ba93da8e5..b950cea79ed 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -2,8 +2,16 @@ # Exit if anything fails set -e +# Prefer rustc in the same directory as this script +DIR="$(dirname "$0")" +if [ -x "$DIR/rustc" ]; then + RUSTC="$DIR/rustc" +else + RUSTC="rustc" +fi + # Find out where the pretty printer Python module is -RUSTC_SYSROOT=`rustc --print=sysroot` +RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)" GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers diff --git a/src/etc/rust-gdbgui b/src/etc/rust-gdbgui index 08d598cde1c..9744913b686 100755 --- a/src/etc/rust-gdbgui +++ b/src/etc/rust-gdbgui @@ -31,8 +31,16 @@ icon to start your program running. exit 0 fi +# Prefer rustc in the same directory as this script +DIR="$(dirname "$0")" +if [ -x "$DIR/rustc" ]; then + RUSTC="$DIR/rustc" +else + RUSTC="rustc" +fi + # Find out where the pretty printer Python module is -RUSTC_SYSROOT=`rustc --print=sysroot` +RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)" GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Set the environment variable `RUST_GDB` to overwrite the call to a diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index a48e48d7da3..7ef281ff208 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -964,8 +964,16 @@ impl<T> Vec<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { + #[cold] + #[inline(never)] + fn assert_failed(index: usize, len: usize) -> ! { + panic!("swap_remove index (is {}) should be < len (is {})", index, len); + } + let len = self.len(); - assert!(index < len); + if !(index < len) { + assert_failed(index, len); + } unsafe { // We replace self[index] with the last element. Note that if the // bounds check above succeeds there must be a last element (which @@ -995,8 +1003,16 @@ impl<T> Vec<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, index: usize, element: T) { + #[cold] + #[inline(never)] + fn assert_failed(index: usize, len: usize) -> ! { + panic!("insertion index (is {}) should be <= len (is {})", index, len); + } + let len = self.len(); - assert!(index <= len); + if !(index <= len) { + assert_failed(index, len); + } // space for the new element if len == self.buf.capacity() { @@ -1035,8 +1051,16 @@ impl<T> Vec<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, index: usize) -> T { + #[cold] + #[inline(never)] + fn assert_failed(index: usize, len: usize) -> ! { + panic!("removal index (is {}) should be < len (is {})", index, len); + } + let len = self.len(); - assert!(index < len); + if !(index < len) { + assert_failed(index, len); + } unsafe { // infallible let ret; @@ -1294,8 +1318,25 @@ impl<T> Vec<T> { Excluded(&n) => n, Unbounded => len, }; - assert!(start <= end); - assert!(end <= len); + + #[cold] + #[inline(never)] + fn start_assert_failed(start: usize, end: usize) -> ! { + panic!("start drain index (is {}) should be <= end drain index (is {})", start, end); + } + + #[cold] + #[inline(never)] + fn end_assert_failed(end: usize, len: usize) -> ! { + panic!("end drain index (is {}) should be <= len (is {})", end, len); + } + + if !(start <= end) { + start_assert_failed(start, end); + } + if !(end <= len) { + end_assert_failed(end, len); + } unsafe { // set self.vec length's to start, to be safe in case Drain is leaked @@ -1385,7 +1426,15 @@ impl<T> Vec<T> { #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] pub fn split_off(&mut self, at: usize) -> Self { - assert!(at <= self.len(), "`at` out of bounds"); + #[cold] + #[inline(never)] + fn assert_failed(at: usize, len: usize) -> ! { + panic!("`at` split index (is {}) should be <= len (is {})", at, len); + } + + if !(at <= self.len()) { + assert_failed(at, self.len()); + } let other_len = self.len - at; let mut other = Vec::with_capacity(other_len); diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 0a2a0e9e045..f791fe82a27 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -47,9 +47,6 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "hermit")] { #[path = "hermit.rs"] mod real_imp; - } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { - #[path = "dummy.rs"] - mod real_imp; } else if #[cfg(target_env = "msvc")] { #[path = "seh.rs"] mod real_imp; diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 10b765a5b41..9eff37f1766 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -117,7 +117,7 @@ mod imp { } } -#[cfg(any(target_arch = "x86_64", target_arch = "arm"))] +#[cfg(not(target_arch = "x86"))] #[macro_use] mod imp { pub type ptr_t = u32; diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 6586280d214..f91cbe51d85 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -300,8 +300,8 @@ pub enum GenericBound { impl GenericBound { pub fn span(&self) -> Span { match self { - &GenericBound::Trait(ref t, ..) => t.span, - &GenericBound::Outlives(ref l) => l.ident.span, + GenericBound::Trait(ref t, ..) => t.span, + GenericBound::Outlives(ref l) => l.ident.span, } } } diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 6005b607026..5fe007d6de2 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -165,19 +165,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::MacroDef(..) => SmallVec::new(), ItemKind::Fn(..) | ItemKind::Impl { of_trait: None, .. } => smallvec![i.id], - ItemKind::Static(ref ty, ..) => { + ItemKind::Static(ref ty, ..) | ItemKind::Const(_, ref ty, ..) => { let mut ids = smallvec![i.id]; if self.sess.features_untracked().impl_trait_in_bindings { - let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; - visitor.visit_ty(ty); - } - ids - } - ItemKind::Const(_, ref ty, ..) => { - let mut ids = smallvec![i.id]; - if self.sess.features_untracked().impl_trait_in_bindings { - let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; - visitor.visit_ty(ty); + ImplTraitTypeIdVisitor { ids: &mut ids }.visit_ty(ty); } ids } diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml index 5d096e4965d..e4d1d79abb2 100644 --- a/src/librustc_ast_passes/Cargo.toml +++ b/src/librustc_ast_passes/Cargo.toml @@ -9,6 +9,7 @@ name = "rustc_ast_passes" path = "lib.rs" [dependencies] +itertools = "0.8" log = "0.4" rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index de7ae10723f..9563325fe32 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -6,6 +6,7 @@ // This pass is supposed to perform only simple checks not requiring name resolution // or type checking or some other kind of complex analysis. +use itertools::{Either, Itertools}; use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::expand::is_proc_macro_attr; @@ -14,7 +15,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::walk_list; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, struct_span_err, Applicability}; +use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; @@ -640,6 +641,33 @@ impl<'a> AstValidator<'a> { } } + fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String { + // Lifetimes always come first. + let lt_sugg = data.args.iter().filter_map(|arg| match arg { + AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => { + Some(pprust::to_string(|s| s.print_generic_arg(lt))) + } + _ => None, + }); + let args_sugg = data.args.iter().filter_map(|a| match a { + AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => { + None + } + AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))), + }); + // Constraints always come last. + let constraint_sugg = data.args.iter().filter_map(|a| match a { + AngleBracketedArg::Arg(_) => None, + AngleBracketedArg::Constraint(c) => { + Some(pprust::to_string(|s| s.print_assoc_constraint(c))) + } + }); + format!( + "<{}>", + lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ") + ) + } + /// Enforce generic args coming before constraints in `<...>` of a path segment. fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { // Early exit in case it's partitioned as it should be. @@ -647,24 +675,36 @@ impl<'a> AstValidator<'a> { return; } // Find all generic argument coming after the first constraint... - let mut misplaced_args = Vec::new(); - let mut first = None; - for arg in &data.args { - match (arg, first) { - (AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()), - (AngleBracketedArg::Constraint(c), None) => first = Some(c.span), - (AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => { - } - } - } + let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) = + data.args.iter().partition_map(|arg| match arg { + AngleBracketedArg::Constraint(c) => Either::Left(c.span), + AngleBracketedArg::Arg(a) => Either::Right(a.span()), + }); + let args_len = arg_spans.len(); + let constraint_len = constraint_spans.len(); // ...and then error: self.err_handler() .struct_span_err( - misplaced_args.clone(), + arg_spans.clone(), "generic arguments must come before the first constraint", ) - .span_label(first.unwrap(), "the first constraint is provided here") - .span_labels(misplaced_args, "generic argument") + .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len))) + .span_label( + *arg_spans.iter().last().unwrap(), + &format!("generic argument{}", pluralize!(args_len)), + ) + .span_labels(constraint_spans, "") + .span_labels(arg_spans, "") + .span_suggestion_verbose( + data.span, + &format!( + "move the constraint{} after the generic argument{}", + pluralize!(constraint_len), + pluralize!(args_len) + ), + self.correct_generic_order_suggestion(&data), + Applicability::MachineApplicable, + ) .emit(); } } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 6541ac156b4..f68868633f1 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -869,7 +869,7 @@ impl<'a> State<'a> { } } - fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { + pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { self.print_ident(constraint.ident); self.s.space(); match &constraint.kind { @@ -883,7 +883,7 @@ impl<'a> State<'a> { } } - crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) { + pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) { match generic_arg { GenericArg::Lifetime(lt) => self.print_lifetime(*lt), GenericArg::Type(ty) => self.print_type(ty), diff --git a/src/librustc_error_codes/error_codes/E0501.md b/src/librustc_error_codes/error_codes/E0501.md index f5aa17a8094..ffdbc443905 100644 --- a/src/librustc_error_codes/error_codes/E0501.md +++ b/src/librustc_error_codes/error_codes/E0501.md @@ -1,12 +1,4 @@ -This error indicates that a mutable variable is being used while it is still -captured by a closure. Because the closure has borrowed the variable, it is not -available for use until the closure goes out of scope. - -Note that a capture will either move or borrow a variable, but in this -situation, the closure is borrowing the variable. Take a look at the chapter -on [Capturing][capturing] in Rust By Example for more information. - -[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html +A mutable variable is used but it is already captured by a closure. Erroneous code example: @@ -29,6 +21,16 @@ fn foo(a: &mut i32) { } ``` +This error indicates that a mutable variable is used while it is still captured +by a closure. Because the closure has borrowed the variable, it is not available +until the closure goes out of scope. + +Note that a capture will either move or borrow a variable, but in this +situation, the closure is borrowing the variable. Take a look at the chapter +on [Capturing][capturing] in Rust By Example for more information. + +[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html + To fix this error, you can finish using the closure before using the captured variable: diff --git a/src/librustc_error_codes/error_codes/E0506.md b/src/librustc_error_codes/error_codes/E0506.md index 9b8e3164872..c312a0460e3 100644 --- a/src/librustc_error_codes/error_codes/E0506.md +++ b/src/librustc_error_codes/error_codes/E0506.md @@ -1,4 +1,4 @@ -This error occurs when an attempt is made to assign to a borrowed value. +An attempt was made to assign to a borrowed value. Erroneous code example: @@ -7,14 +7,12 @@ struct FancyNum { num: u8, } -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - fancy_num = FancyNum { num: 6 }; - // error: cannot assign to `fancy_num` because it is borrowed +let mut fancy_num = FancyNum { num: 5 }; +let fancy_ref = &fancy_num; +fancy_num = FancyNum { num: 6 }; +// error: cannot assign to `fancy_num` because it is borrowed - println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); -} +println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); ``` Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't @@ -27,13 +25,11 @@ struct FancyNum { num: u8, } -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let moved_num = fancy_num; - fancy_num = FancyNum { num: 6 }; +let mut fancy_num = FancyNum { num: 5 }; +let moved_num = fancy_num; +fancy_num = FancyNum { num: 6 }; - println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); -} +println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); ``` If the value has to be borrowed, try limiting the lifetime of the borrow using @@ -44,18 +40,16 @@ struct FancyNum { num: u8, } -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - { - let fancy_ref = &fancy_num; - println!("Ref: {}", fancy_ref.num); - } +let mut fancy_num = FancyNum { num: 5 }; - // Works because `fancy_ref` is no longer in scope - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); +{ + let fancy_ref = &fancy_num; + println!("Ref: {}", fancy_ref.num); } + +// Works because `fancy_ref` is no longer in scope +fancy_num = FancyNum { num: 6 }; +println!("Num: {}", fancy_num.num); ``` Or by moving the reference into a function: @@ -65,17 +59,15 @@ struct FancyNum { num: u8, } -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - print_fancy_ref(&fancy_num); - - // Works because function borrow has ended - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); -} - fn print_fancy_ref(fancy_ref: &FancyNum){ println!("Ref: {}", fancy_ref.num); } + +let mut fancy_num = FancyNum { num: 5 }; + +print_fancy_ref(&fancy_num); + +// Works because function borrow has ended +fancy_num = FancyNum { num: 6 }; +println!("Num: {}", fancy_num.num); ``` diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index fffae0bfd24..2dbd9f4e52f 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -315,6 +315,20 @@ impl<'a> DiagnosticBuilder<'a> { self } + pub fn span_suggestion_verbose( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + if !self.0.allow_suggestions { + return self; + } + self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability); + self + } + pub fn span_suggestion_hidden( &mut self, sp: Span, diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 7824855fe05..bb6e5700cca 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -7,52 +7,59 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Infer, Ty, TyVar}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; use std::borrow::Cow; -struct FindLocalByTypeVisitor<'a, 'tcx> { +struct FindHirNodeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - target_ty: Ty<'tcx>, - hir_map: Map<'tcx>, + target: GenericArg<'tcx>, + found_node_ty: Option<Ty<'tcx>>, found_local_pattern: Option<&'tcx Pat<'tcx>>, found_arg_pattern: Option<&'tcx Pat<'tcx>>, - found_ty: Option<Ty<'tcx>>, - found_closure: Option<&'tcx ExprKind<'tcx>>, + found_closure: Option<&'tcx Expr<'tcx>>, found_method_call: Option<&'tcx Expr<'tcx>>, } -impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: Map<'tcx>) -> Self { +impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { + fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self { Self { infcx, - target_ty, - hir_map, + target, + found_node_ty: None, found_local_pattern: None, found_arg_pattern: None, - found_ty: None, found_closure: None, found_method_call: None, } } - fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> { + fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id)); match ty_opt { Some(ty) => { let ty = self.infcx.resolve_vars_if_possible(&ty); - if ty.walk().any(|inner_ty| { - inner_ty == self.target_ty - || match (&inner_ty.kind, &self.target_ty.kind) { - (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self - .infcx - .inner - .borrow_mut() - .type_variables - .sub_unified(a_vid, b_vid), + if ty.walk().any(|inner| { + inner == self.target + || match (inner.unpack(), self.target.unpack()) { + (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { + match (&inner_ty.kind, &target_ty.kind) { + ( + &ty::Infer(ty::TyVar(a_vid)), + &ty::Infer(ty::TyVar(b_vid)), + ) => self + .infcx + .inner + .borrow_mut() + .type_variables + .sub_unified(a_vid, b_vid), + _ => false, + } + } _ => false, } }) { @@ -66,36 +73,39 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::OnlyBodies(self.hir_map) + NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir()) } fn visit_local(&mut self, local: &'tcx Local<'tcx>) { - if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) { + if let (None, Some(ty)) = + (self.found_local_pattern, self.node_ty_contains_target(local.hir_id)) + { self.found_local_pattern = Some(&*local.pat); - self.found_ty = Some(ty); + self.found_node_ty = Some(ty); } intravisit::walk_local(self, local); } fn visit_body(&mut self, body: &'tcx Body<'tcx>) { for param in body.params { - if let (None, Some(ty)) = (self.found_arg_pattern, self.node_matches_type(param.hir_id)) + if let (None, Some(ty)) = + (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id)) { self.found_arg_pattern = Some(&*param.pat); - self.found_ty = Some(ty); + self.found_node_ty = Some(ty); } } intravisit::walk_body(self, body); } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.node_matches_type(expr.hir_id).is_some() { + if self.node_ty_contains_target(expr.hir_id).is_some() { match expr.kind { - ExprKind::Closure(..) => self.found_closure = Some(&expr.kind), + ExprKind::Closure(..) => self.found_closure = Some(&expr), ExprKind::MethodCall(..) => self.found_method_call = Some(&expr), _ => {} } @@ -213,6 +223,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (s, None, ty.prefix_string(), None, None) } + // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. pub fn need_type_info_err( &self, body_id: Option<hir::BodyId>, @@ -223,7 +234,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, self.tcx.hir()); + let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into()); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -276,7 +287,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) }; - let ty_msg = match local_visitor.found_ty { + let ty_msg = match local_visitor.found_node_ty { Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); @@ -310,28 +321,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_code, ); - let suffix = match local_visitor.found_ty { + let suffix = match local_visitor.found_node_ty { Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { let fn_sig = substs.as_closure().sig(); let ret = fn_sig.output().skip_binder().to_string(); - if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure { - if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) { - closure_return_type_suggestion( - span, - &mut err, - &decl.output, - &body, - &descr, - &name, - &ret, - parent_name, - parent_descr, - ); - // We don't want to give the other suggestions when the problem is the - // closure return type. - return err; - } + let closure_decl_and_body_id = + local_visitor.found_closure.and_then(|closure| match &closure.kind { + ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)), + _ => None, + }); + + if let Some((decl, body_id)) = closure_decl_and_body_id { + closure_return_type_suggestion( + span, + &mut err, + &decl.output, + self.tcx.hir().body(body_id), + &descr, + &name, + &ret, + parent_name, + parent_descr, + ); + // We don't want to give the other suggestions when the problem is the + // closure return type. + return err; } // This shouldn't be reachable, but just in case we leave a reasonable fallback. diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 1cd6830b6a2..ed967f7ab3a 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -3,11 +3,9 @@ use crate::infer::{GenericKind, VerifyBound}; use crate::traits; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use smallvec::smallvec; - /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` /// obligation into a series of `'a: 'b` constraints and "verifys", as /// described on the module comment. The final constraints are emitted @@ -44,7 +42,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match ty.kind { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data), - _ => self.recursive_type_bound(ty), + _ => self.recursive_bound(ty.into()), } } @@ -144,25 +142,33 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - let recursive_bound = self.recursive_type_bound(ty); + let recursive_bound = self.recursive_bound(ty.into()); VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) } - fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>(); - - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions - bounds.push(VerifyBound::AllBounds( - regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect(), - )); - - // remove bounds that must hold, since they are not interesting - bounds.retain(|b| !b.must_hold()); + fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> { + let mut bounds = parent + .walk_shallow() + .filter_map(|child| match child.unpack() { + GenericArgKind::Type(ty) => Some(self.type_bound(ty)), + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None } + } + GenericArgKind::Const(_) => Some(self.recursive_bound(child)), + }) + .filter(|bound| { + // Remove bounds that must hold, since they are not interesting. + !bound.must_hold() + }); - if bounds.len() == 1 { bounds.pop().unwrap() } else { VerifyBound::AllBounds(bounds) } + match (bounds.next(), bounds.next()) { + (Some(first), None) => first, + (first, second) => { + VerifyBound::AllBounds(first.into_iter().chain(second).chain(bounds).collect()) + } + } } /// Searches the environment for where-clauses like `G: 'a` where diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cff86e8f218..84cf2258ac2 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -36,6 +36,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{GenericParamKind, PatKind}; use rustc_hir::{HirIdSet, Node}; use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::edition::Edition; @@ -104,11 +105,13 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) { - for leaf_ty in ty.walk() { - if leaf_ty.is_box() { - cx.struct_span_lint(BOX_POINTERS, span, |lint| { - lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit() - }); + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if leaf_ty.is_box() { + cx.struct_span_lint(BOX_POINTERS, span, |lint| { + lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit() + }); + } } } } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index a3d611a1325..7b23460eb6e 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -263,20 +263,6 @@ where // Region folder impl<'tcx> TyCtxt<'tcx> { - /// Collects the free and escaping regions in `value` into `region_set`. Returns - /// whether any late-bound regions were skipped - pub fn collect_regions<T>(self, value: &T, region_set: &mut FxHashSet<ty::Region<'tcx>>) -> bool - where - T: TypeFoldable<'tcx>, - { - let mut have_bound_regions = false; - self.fold_regions(value, &mut have_bound_regions, |r, d| { - region_set.insert(self.mk_region(r.shifted_out_to_binder(d))); - r - }); - have_bound_regions - } - /// Folds the escaping and free regions in `value` using `f`, and /// sets `skipped_regions` to true if any late-bound region was found /// and skipped. diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 0ebd55a6c02..1870856150f 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -19,7 +19,6 @@ use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; -use crate::ty::walk::TypeWalker; use rustc_ast::ast::{self, Ident, Name}; use rustc_ast::node_id::{NodeId, NodeMap, NodeSet}; use rustc_attr as attr; @@ -1366,10 +1365,6 @@ impl<'tcx> TraitPredicate<'tcx> { self.trait_ref.def_id } - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { - self.trait_ref.input_types() - } - pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } @@ -1519,77 +1514,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } -// A custom iterator used by `Predicate::walk_tys`. -enum WalkTysIter<'tcx, I, J, K> -where - I: Iterator<Item = Ty<'tcx>>, - J: Iterator<Item = Ty<'tcx>>, - K: Iterator<Item = Ty<'tcx>>, -{ - None, - One(Ty<'tcx>), - Two(Ty<'tcx>, Ty<'tcx>), - Types(I), - InputTypes(J), - ProjectionTypes(K), -} - -impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> -where - I: Iterator<Item = Ty<'tcx>>, - J: Iterator<Item = Ty<'tcx>>, - K: Iterator<Item = Ty<'tcx>>, -{ - type Item = Ty<'tcx>; - - fn next(&mut self) -> Option<Ty<'tcx>> { - match *self { - WalkTysIter::None => None, - WalkTysIter::One(item) => { - *self = WalkTysIter::None; - Some(item) - } - WalkTysIter::Two(item1, item2) => { - *self = WalkTysIter::One(item2); - Some(item1) - } - WalkTysIter::Types(ref mut iter) => iter.next(), - WalkTysIter::InputTypes(ref mut iter) => iter.next(), - WalkTysIter::ProjectionTypes(ref mut iter) => iter.next(), - } - } -} - impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a { - match *self { - ty::Predicate::Trait(ref data, _) => { - WalkTysIter::InputTypes(data.skip_binder().input_types()) - } - ty::Predicate::Subtype(binder) => { - let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - WalkTysIter::Two(a, b) - } - ty::Predicate::TypeOutlives(binder) => WalkTysIter::One(binder.skip_binder().0), - ty::Predicate::RegionOutlives(..) => WalkTysIter::None, - ty::Predicate::Projection(ref data) => { - let inner = data.skip_binder(); - WalkTysIter::ProjectionTypes( - inner.projection_ty.substs.types().chain(Some(inner.ty)), - ) - } - ty::Predicate::WellFormed(data) => WalkTysIter::One(data), - ty::Predicate::ObjectSafe(_trait_def_id) => WalkTysIter::None, - ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - WalkTysIter::Types(closure_substs.types()) - } - ty::Predicate::ConstEvaluatable(_, substs) => WalkTysIter::Types(substs.types()), - } - } - pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> { match *self { Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), @@ -2686,46 +2611,6 @@ impl<'tcx> ClosureKind { } } -impl<'tcx> TyS<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```notrust - /// isize => { isize } - /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]` - /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter<walk::TypeWalkerArray<'tcx>> { - walk::walk_shallow(self) - } - - /// Walks `ty` and any types appearing within `ty`, invoking the - /// callback `f` on each type. If the callback returns `false`, then the - /// children of the current type are ignored. - /// - /// Note: prefer `ty.walk()` where possible. - pub fn maybe_walk<F>(&'tcx self, mut f: F) - where - F: FnMut(Ty<'tcx>) -> bool, - { - let mut walker = self.walk(); - while let Some(ty) = walker.next() { - if !f(ty) { - walker.skip_current_subtree(); - } - } - } -} - impl BorrowKind { pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { match m { diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 9dd96f2f2b5..950539fbb0a 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -2,6 +2,7 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. +use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use smallvec::SmallVec; @@ -107,8 +108,9 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // fallback case: hard code // OutlivesProjectionComponents. Continue walking // through and constrain Pi. - let subcomponents = capture_components(tcx, ty); - out.push(Component::EscapingProjection(subcomponents)); + let mut subcomponents = smallvec![]; + compute_components_recursive(tcx, ty.into(), &mut subcomponents); + out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); } } @@ -153,26 +155,30 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // "bound regions list". In our representation, no such // list is maintained explicitly, because bound regions // themselves can be readily identified. - - push_region_constraints(ty, out); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, out); - } + compute_components_recursive(tcx, ty.into(), out); } } } -fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> { - let mut temp = smallvec![]; - push_region_constraints(ty, &mut temp); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, &mut temp); +fn compute_components_recursive( + tcx: TyCtxt<'tcx>, + parent: GenericArg<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, +) { + for child in parent.walk_shallow() { + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out); + } + } } - temp.into_iter().collect() -} - -fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r))); } diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index ef815aaab75..f0932788687 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -25,7 +25,6 @@ use rustc_macros::HashStable; use rustc_span::symbol::{kw, Symbol}; use rustc_target::abi::{Size, VariantIdx}; use rustc_target::spec::abi; -use smallvec::SmallVec; use std::borrow::Cow; use std::cmp::Ordering; use std::marker::PhantomData; @@ -755,14 +754,6 @@ impl<'tcx> TraitRef<'tcx> { self.substs.type_at(0) } - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - pub fn from_method( tcx: TyCtxt<'tcx>, trait_id: DefId, @@ -806,14 +797,6 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'b { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - pub fn erase_self_ty( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -2152,31 +2135,6 @@ impl<'tcx> TyS<'tcx> { } } - /// Pushes onto `out` the regions directly referenced from this type (but not - /// types reachable from this type via `walk_tys`). This ignores late-bound - /// regions binders. - pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) { - match self.kind { - Ref(region, _, _) => { - out.push(region); - } - Dynamic(ref obj, region) => { - out.push(region); - if let Some(principal) = obj.principal() { - out.extend(principal.skip_binder().substs.regions()); - } - } - Adt(_, substs) | Opaque(_, substs) => out.extend(substs.regions()), - Closure(_, ref substs) | Generator(_, ref substs, _) => out.extend(substs.regions()), - Projection(ref data) | UnnormalizedProjection(ref data) => { - out.extend(data.substs.regions()) - } - FnDef(..) | FnPtr(_) | GeneratorWitness(..) | Bool | Char | Int(_) | Uint(_) - | Float(_) | Str | Array(..) | Slice(_) | RawPtr(_) | Never | Tuple(..) - | Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {} - } - } - /// When we create a closure, we record its kind (i.e., what trait /// it implements) into its `ClosureSubsts` using a type /// parameter. This is kind of a phantom type, except that the diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs index da08fbcf144..c7a317f39ad 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/src/librustc_middle/ty/walk.rs @@ -1,13 +1,13 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use crate::ty::{self, Ty}; +use crate::ty; +use crate::ty::subst::{GenericArg, GenericArgKind}; use smallvec::{self, SmallVec}; // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. -pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8]; -pub type TypeWalkerStack<'tcx> = SmallVec<TypeWalkerArray<'tcx>>; +type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { stack: TypeWalkerStack<'tcx>, @@ -15,11 +15,11 @@ pub struct TypeWalker<'tcx> { } impl<'tcx> TypeWalker<'tcx> { - pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: smallvec![ty], last_subtree: 1 } + pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> { + TypeWalker { stack: smallvec![root], last_subtree: 1 } } - /// Skips the subtree of types corresponding to the last type + /// Skips the subtree corresponding to the last type /// returned by `next()`. /// /// Example: Imagine you are walking `Foo<Bar<int>, usize>`. @@ -37,102 +37,145 @@ impl<'tcx> TypeWalker<'tcx> { } impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = Ty<'tcx>; + type Item = GenericArg<'tcx>; - fn next(&mut self) -> Option<Ty<'tcx>> { + fn next(&mut self) -> Option<GenericArg<'tcx>> { debug!("next(): stack={:?}", self.stack); - match self.stack.pop() { - None => None, - Some(ty) => { - self.last_subtree = self.stack.len(); - push_subtypes(&mut self.stack, ty); - debug!("next: stack={:?}", self.stack); - Some(ty) - } - } + let next = self.stack.pop()?; + self.last_subtree = self.stack.len(); + push_inner(&mut self.stack, next); + debug!("next: stack={:?}", self.stack); + Some(next) } } -pub fn walk_shallow(ty: Ty<'_>) -> smallvec::IntoIter<TypeWalkerArray<'_>> { - let mut stack = SmallVec::new(); - push_subtypes(&mut stack, ty); - stack.into_iter() +impl GenericArg<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```notrust + /// isize => { isize } + /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker<'tcx> { + TypeWalker::new(self) + } + + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(self) -> impl Iterator<Item = GenericArg<'tcx>> { + let mut stack = SmallVec::new(); + push_inner(&mut stack, self); + stack.into_iter() + } } -// We push types on the stack in reverse order so as to +impl<'tcx> super::TyS<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```notrust + /// isize => { isize } + /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(&'tcx self) -> TypeWalker<'tcx> { + TypeWalker::new(self.into()) + } +} + +// We push `GenericArg`s on the stack in reverse order so as to // maintain a pre-order traversal. As of the time of this // writing, the fact that the traversal is pre-order is not // known to be significant to any code, but it seems like the // natural order one would expect (basically, the order of the // types as they are written). -fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { - match parent_ty.kind { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Infer(_) - | ty::Param(_) - | ty::Never - | ty::Error - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Foreign(..) => {} - ty::Array(ty, len) => { - if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val { - assert!(promoted.is_none()); - stack.extend(substs.types().rev()); +fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { + match parent.unpack() { + GenericArgKind::Type(parent_ty) => match parent_ty.kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Infer(_) + | ty::Param(_) + | ty::Never + | ty::Error + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Foreign(..) => {} + + ty::Array(ty, len) => { + stack.push(len.into()); + stack.push(ty.into()); } - stack.push(len.ty); - stack.push(ty); - } - ty::Slice(ty) => { - stack.push(ty); - } - ty::RawPtr(ref mt) => { - stack.push(mt.ty); - } - ty::Ref(_, ty, _) => { - stack.push(ty); - } - ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { - stack.extend(data.substs.types().rev()); - } - ty::Dynamic(ref obj, ..) => { - stack.extend(obj.iter().rev().flat_map(|predicate| { - let (substs, opt_ty) = match *predicate.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), - ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), - ty::ExistentialPredicate::AutoTrait(_) => - // Empty iterator - { - (ty::InternalSubsts::empty(), None) - } - }; + ty::Slice(ty) => { + stack.push(ty.into()); + } + ty::RawPtr(mt) => { + stack.push(mt.ty.into()); + } + ty::Ref(lt, ty, _) => { + stack.push(ty.into()); + stack.push(lt.into()); + } + ty::Projection(data) | ty::UnnormalizedProjection(data) => { + stack.extend(data.substs.iter().copied().rev()); + } + ty::Dynamic(obj, lt) => { + stack.push(lt.into()); + stack.extend(obj.iter().rev().flat_map(|predicate| { + let (substs, opt_ty) = match *predicate.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), + ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), + ty::ExistentialPredicate::AutoTrait(_) => + // Empty iterator + { + (ty::InternalSubsts::empty(), None) + } + }; - substs.types().rev().chain(opt_ty) - })); - } - ty::Adt(_, substs) | ty::Opaque(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::Closure(_, ref substs) | ty::Generator(_, ref substs, _) => { - stack.extend(substs.types().rev()); - } - ty::GeneratorWitness(ts) => { - stack.extend(ts.skip_binder().iter().cloned().rev()); - } - ty::Tuple(..) => { - stack.extend(parent_ty.tuple_fields().rev()); - } - ty::FnDef(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::FnPtr(sig) => { - stack.push(sig.skip_binder().output()); - stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); + substs.iter().copied().rev().chain(opt_ty.map(|ty| ty.into())) + })); + } + ty::Adt(_, substs) + | ty::Opaque(_, substs) + | ty::Closure(_, substs) + | ty::Generator(_, substs, _) + | ty::Tuple(substs) + | ty::FnDef(_, substs) => { + stack.extend(substs.iter().copied().rev()); + } + ty::GeneratorWitness(ts) => { + stack.extend(ts.skip_binder().iter().cloned().rev().map(|ty| ty.into())); + } + ty::FnPtr(sig) => { + stack.push(sig.skip_binder().output().into()); + stack.extend(sig.skip_binder().inputs().iter().cloned().rev().map(|ty| ty.into())); + } + }, + GenericArgKind::Lifetime(_) => {} + GenericArgKind::Const(parent_ct) => { + stack.push(parent_ct.ty.into()); + match parent_ct.val { + ty::ConstKind::Infer(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Value(_) => {} + + ty::ConstKind::Unevaluated(_, substs, _) => { + stack.extend(substs.iter().copied().rev()); + } + } } } } diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 7340e88f19b..7645182ad1f 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -208,45 +208,34 @@ impl BorrowExplanation { ); }; - self.add_lifetime_bound_suggestion_to_diagnostic( - tcx, - err, - &category, - span, - region_name, - ); + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); } _ => {} } } - pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic<'tcx>( + pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic( &self, - tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>, category: &ConstraintCategory, span: Span, region_name: &RegionName, ) { if let ConstraintCategory::OpaqueType = category { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { - let suggestable_name = if region_name.was_named() { - region_name.to_string() - } else { - "'_".to_string() - }; + let suggestable_name = + if region_name.was_named() { region_name.to_string() } else { "'_".to_string() }; - err.span_suggestion( - span, - &format!( - "you can add a bound to the {}to make it last less than \ - `'static` and match `{}`", - category.description(), - region_name, - ), - format!("{} + {}", snippet, suggestable_name), - Applicability::Unspecified, - ); - } + let msg = format!( + "you can add a bound to the {}to make it last less than `'static` and match `{}`", + category.description(), + region_name, + ); + + err.span_suggestion_verbose( + span.shrink_to_hi(), + &msg, + format!(" + {}", suggestable_name), + Applicability::Unspecified, + ); } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 0b182d42287..72d20644fe8 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{self, TyAndLayout}; use rustc_middle::ty::{ self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable, }; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::{source_map::DUMMY_SP, Span}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use super::{ @@ -256,7 +256,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( /// or compute the layout. #[cfg_attr(not(debug_assertions), inline(always))] pub(super) fn from_known_layout<'tcx>( - tcx: TyCtxt<'tcx>, + tcx: TyCtxtAt<'tcx>, known_layout: Option<TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -265,12 +265,14 @@ pub(super) fn from_known_layout<'tcx>( Some(known_layout) => { if cfg!(debug_assertions) { let check_layout = compute()?; - assert!( - mir_assign_valid_types(tcx, check_layout, known_layout), - "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", - known_layout.ty, - check_layout.ty, - ); + if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) { + span_bug!( + tcx.span, + "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", + known_layout.ty, + check_layout.ty, + ); + } } Ok(known_layout) } @@ -295,6 +297,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] + pub fn set_span(&mut self, span: Span) { + self.tcx.span = span; + self.memory.tcx.span = span; + } + + #[inline(always)] pub fn force_ptr( &self, scalar: Scalar<M::PointerTag>, @@ -444,7 +452,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // have to support that case (mostly by skipping all caching). match frame.locals.get(local).and_then(|state| state.layout.get()) { None => { - let layout = from_known_layout(self.tcx.tcx, layout, || { + let layout = from_known_layout(self.tcx, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 03614b2803f..3741f31927e 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -529,7 +529,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Value(val_val) => val_val, }; // Other cases need layout. - let layout = from_known_layout(self.tcx.tcx, layout, || self.layout_of(val.ty))?; + let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 716c7c7d933..828df9a0930 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -867,12 +867,14 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - assert!( - mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout), - "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", - src.layout.ty, - dest.layout.ty, - ); + if !mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { + span_bug!( + self.tcx.span, + "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", + src.layout.ty, + dest.layout.ty, + ); + } // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. let src = match self.try_read_immediate(src)? { diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 407849c2ce2..37740878f70 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -78,14 +78,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { info!("{:?}", stmt); + self.set_span(stmt.source_info.span); use rustc_middle::mir::StatementKind::*; // Some statements (e.g., box) push new stack frames. // We have to record the stack frame number *before* executing the statement. let frame_idx = self.cur_frame(); - self.tcx.span = stmt.source_info.span; - self.memory.tcx.span = stmt.source_info.span; match &stmt.kind { Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, @@ -276,16 +275,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { info!("{:?}", terminator.kind); - self.tcx.span = terminator.source_info.span; - self.memory.tcx.span = terminator.source_info.span; - - let old_stack = self.cur_frame(); - let old_bb = self.frame().block; + self.set_span(terminator.source_info.span); self.eval_terminator(terminator)?; if !self.stack.is_empty() { - // This should change *something* - assert!(self.cur_frame() != old_stack || self.frame().block != old_bb); if let Some(block) = self.frame().block { info!("// executing {:?}", block); } diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 6ebe5b80370..2d8551b2bbf 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -52,6 +52,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Call { ref func, ref args, destination, ref cleanup, .. } => { + let old_stack = self.cur_frame(); + let old_bb = self.frame().block; let func = self.eval_operand(func, None)?; let (fn_val, abi) = match func.layout.ty.kind { ty::FnPtr(sig) => { @@ -64,7 +66,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let sig = func.layout.ty.fn_sig(*self.tcx); (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi()) } - _ => bug!("invalid callee of type {:?}", func.layout.ty), + _ => span_bug!( + terminator.source_info.span, + "invalid callee of type {:?}", + func.layout.ty + ), }; let args = self.eval_operands(args)?; let ret = match destination { @@ -72,6 +78,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => None, }; self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?; + // Sanity-check that `eval_fn_call` either pushed a new frame or + // did a jump to another block. + if self.cur_frame() == old_stack && self.frame().block == old_bb { + span_bug!(terminator.source_info.span, "evaluating this call made no progress"); + } } Drop { location, target, unwind } => { @@ -116,9 +127,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | FalseEdges { .. } | FalseUnwind { .. } | Yield { .. } - | GeneratorDrop => { - bug!("{:#?} should have been eliminated by MIR pass", terminator.kind) - } + | GeneratorDrop => span_bug!( + terminator.source_info.span, + "{:#?} should have been eliminated by MIR pass", + terminator.kind + ), } Ok(()) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1032ff413af..d8ceda96a25 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -191,7 +191,7 @@ use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::obsolete::DefPathBasedNames; -use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::config::EntryFnType; use smallvec::SmallVec; @@ -442,9 +442,16 @@ fn check_recursion_limit<'tcx>( } fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); - let const_length = instance.substs.consts().flat_map(|ct| ct.ty.walk()).count(); - debug!(" => type length={}, const length={}", type_length, const_length); + let type_length = instance + .substs + .iter() + .flat_map(|&arg| arg.walk()) + .filter(|arg| match arg.unpack() { + GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, + GenericArgKind::Lifetime(_) => false, + }) + .count(); + debug!(" => type length={}", type_length); // Rust code can easily create exponentially-long types using only a // polynomial recursion depth. Even with the default recursion @@ -453,11 +460,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. let type_length_limit = *tcx.sess.type_length_limit.get(); - // We include the const length in the type length, as it's better - // to be overly conservative. - // FIXME(const_generics): we should instead uniformly walk through `substs`, - // ignoring lifetimes. - if type_length + const_length > type_length_limit { + if type_length > type_length_limit { // The instance name is already known to be too long for rustc. // Show only the first and last 32 characters to avoid blasting // the user's terminal with thousands of lines of type-name. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index c7f63d24c28..25719d037f9 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -425,8 +425,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> { - self.ecx.tcx.span = c.span; - // FIXME we need to revisit this for #67176 if c.needs_subst() { return None; @@ -435,6 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => Some(op), Err(error) => { + // Make sure errors point at the constant. + self.ecx.set_span(c.span); let err = error_to_const_error(&self.ecx, error); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal.val { @@ -820,6 +820,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { trace!("visit_statement: {:?}", statement); let source_info = statement.source_info; + self.ecx.set_span(source_info.span); self.source_info = Some(source_info); if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty; @@ -870,6 +871,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { let source_info = terminator.source_info; + self.ecx.set_span(source_info.span); self.source_info = Some(source_info); self.super_terminator(terminator, location); match &mut terminator.kind { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c5b366ef572..8f7a1b948e3 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -2,6 +2,7 @@ use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -92,7 +93,15 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - } fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { - for ty in ty.walk() { + for arg in ty.walk() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + match ty.kind { ty::Ref(_, _, hir::Mutability::Mut) => { if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) { diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index 22ce909083d..dbc39169f2b 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -85,7 +85,7 @@ impl LayoutTest<'tcx> { sym::debug => { self.tcx.sess.span_err( item.span, - &format!("layout debugging for type {:?}: {:#?}", ty, *ty_layout), + &format!("layout_of({:?}) = {:#?}", ty, *ty_layout), ); } diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index 6253f183cc4..71cedb208fc 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -2,6 +2,7 @@ use log::debug; use rustc_ast::ast::*; use rustc_ast::token::{self, Token}; use rustc_ast::visit::{self, FnKind}; +use rustc_ast::walk_list; use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; @@ -117,10 +118,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // we must mirror everything that `visit::walk_fn` below does. self.visit_fn_header(&sig.header); visit::walk_fn_decl(self, &sig.decl); - if let Some(body) = body { - let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); - self.with_parent(closure_def, |this| this.visit_block(body)); - } + let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); + self.with_parent(closure_def, |this| walk_list!(this, visit_block, body)); return; } } diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs index 7a46c7da7c3..8c03f1e8a7e 100644 --- a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs +++ b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); @@ -6,9 +6,6 @@ pub fn target() -> TargetResult { base.has_elf_tls = true; base.features = "+neon,+fp-armv8".to_string(); - // FIXME: this shouldn't be panic=abort, it should be panic=unwind - base.panic_strategy = PanicStrategy::Abort; - Ok(Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs b/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs index a793860260c..6a8d148259a 100644 --- a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs +++ b/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs @@ -1,13 +1,10 @@ -use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_uwp_msvc_base::opts(); base.max_atomic_width = Some(64); base.has_elf_tls = true; - // FIXME: this shouldn't be panic=abort, it should be panic=unwind - base.panic_strategy = PanicStrategy::Abort; - Ok(Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs index a642ae98231..f1311382c54 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/src/librustc_trait_selection/traits/coherence.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; +use std::iter; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -378,26 +379,36 @@ fn orphan_check_trait_ref<'tcx>( ty: Ty<'tcx>, in_crate: InCrate, ) -> Vec<Ty<'tcx>> { - if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() { - ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect() - } else { - vec![ty] + // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`, + // or maybe if this should be calling `ty_is_non_local_constructor`. + if ty_is_non_local(tcx, ty, in_crate).is_some() { + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + return inner_tys + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .collect(); + } } + + vec![ty] } let mut non_local_spans = vec![]; - for (i, input_ty) in - trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate() + for (i, input_ty) in trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .enumerate() { debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); - let non_local_tys = ty_is_non_local(input_ty, in_crate); + let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate); if non_local_tys.is_none() { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); return Ok(()); } else if let ty::Param(_) = input_ty.kind { debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); let local_type = trait_ref - .input_types() + .substs + .types() .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()); @@ -416,30 +427,53 @@ fn orphan_check_trait_ref<'tcx>( Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) } -fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> { +fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> { match ty_is_non_local_constructor(ty, in_crate) { Some(ty) => { - if !fundamental_ty(ty) { - Some(vec![ty]) - } else { - let tys: Vec<_> = ty - .walk_shallow() - .filter_map(|t| ty_is_non_local(t, in_crate)) - .flat_map(|i| i) + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + let tys: Vec<_> = inner_tys + .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate)) + .flatten() .collect(); if tys.is_empty() { None } else { Some(tys) } + } else { + Some(vec![ty]) } } None => None, } } -fn fundamental_ty(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Ref(..) => true, - ty::Adt(def, _) => def.is_fundamental(), - _ => false, - } +/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the +/// type parameters of the ADT, or `T`, respectively. For non-fundamental +/// types, returns `None`. +fn fundamental_ty_inner_tys( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option<impl Iterator<Item = Ty<'tcx>>> { + let (first_ty, rest_tys) = match ty.kind { + ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), + ty::Adt(def, substs) if def.is_fundamental() => { + let mut types = substs.types(); + + // FIXME(eddyb) actually validate `#[fundamental]` up-front. + match types.next() { + None => { + tcx.sess.span_err( + tcx.def_span(def.did), + "`#[fundamental]` requires at least one type parameter", + ); + + return None; + } + + Some(first_ty) => (first_ty, types), + } + } + _ => return None, + }; + + Some(iter::once(first_ty).chain(rest_tys)) } fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { @@ -451,6 +485,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { } } +// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`. fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> { debug!("ty_is_non_local_constructor({:?})", ty); diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index fcec29aaa8e..a8fc56d8509 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -22,7 +22,8 @@ use std::fmt; use super::InferCtxtPrivExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -crate trait InferCtxtExt<'tcx> { +// This trait is public to expose the diagnostics methods to clippy. +pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 09a33120ba7..49a4b96f8b7 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -536,18 +536,17 @@ fn trait_ref_type_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec<TyOrConstInferVar<'tcx>> { - trait_ref + selcx + .infcx() + .resolve_vars_if_possible(&trait_ref) .skip_binder() // ok b/c this check doesn't care about regions - // FIXME(eddyb) walk over `GenericArg` to support const infer vars. - .input_types() - .map(|ty| selcx.infcx().resolve_vars_if_possible(&ty)) - // FIXME(eddyb) try using `maybe_walk` to skip *all* subtrees that - // don't contain inference variables, not just the outermost level. - // FIXME(eddyb) use `has_infer_types_or_const`. - .filter(|ty| ty.has_infer_types()) - .flat_map(|ty| ty.walk()) - // FIXME(eddyb) use `TyOrConstInferVar::maybe_from_generic_arg`. - .filter_map(TyOrConstInferVar::maybe_from_ty) + .substs + .iter() + // FIXME(eddyb) try using `skip_current_subtree` to skip everything that + // doesn't contain inference variables, not just the outermost level. + .filter(|arg| arg.has_infer_types_or_consts()) + .flat_map(|arg| arg.walk()) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg) .collect() } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 20b3fa908d2..d9a5b68dc1e 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -16,7 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{Applicability, FatalError}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; @@ -234,7 +234,7 @@ fn predicates_reference_self( tcx.predicates_of(trait_def_id) }; let self_ty = tcx.types.self_param; - let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty); + let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); predicates .predicates .iter() @@ -243,7 +243,7 @@ fn predicates_reference_self( match predicate { ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. - if data.skip_binder().input_types().skip(1).any(has_self_ty) { + if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None @@ -262,12 +262,8 @@ fn predicates_reference_self( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - if data - .skip_binder() - .projection_ty - .trait_ref(tcx) - .input_types() - .skip(1) + if data.skip_binder().projection_ty.trait_ref(tcx).substs[1..] + .iter() .any(has_self_ty) { Some(sp) @@ -725,19 +721,17 @@ fn contains_illegal_self_type_reference<'tcx>( // without knowing what `Self` is. let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None; - let mut error = false; let self_ty = tcx.types.self_param; - ty.maybe_walk(|ty| { - match ty.kind { - ty::Param(_) => { - if ty == self_ty { - error = true; - } - false // no contained types to walk - } + let mut walker = ty.walk(); + while let Some(arg) = walker.next() { + if arg == self_ty.into() { + return true; + } - ty::Projection(ref data) => { + // Special-case projections (everything else is walked normally). + if let GenericArgKind::Type(ty) = arg.unpack() { + if let ty::Projection(ref data) = ty.kind { // This is a projected type `<Foo as SomeTrait>::X`. // Compute supertraits of current trait lazily. @@ -759,17 +753,18 @@ fn contains_illegal_self_type_reference<'tcx>( supertraits.as_ref().unwrap().contains(&projection_trait_ref); if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error + // Do not walk contained types, do not report error, do collect $200. + walker.skip_current_subtree(); } - } - _ => true, // walk contained types, if any + // DO walk contained types, POSSIBLY reporting an error. + } } - }); - error + // Walk contained types, if any. + } + + false } pub fn provide(providers: &mut ty::query::Providers<'_>) { diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 3d95824cdf0..84c264f06db 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -44,7 +44,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::ty::fast_reject; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{ self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; @@ -652,7 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> Result<EvaluationResult, OverflowError> { - // In intercrate mode, whenever any of the types are unbound, + // In intercrate mode, whenever any of the generics are unbound, // there can always be an impl. Even if there are no impls in // this crate, perhaps the type would be unified with // something from another crate that does provide an impl. @@ -677,7 +677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let unbound_input_types = - stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); + stack.fresh_trait_ref.skip_binder().substs.types().any(|ty| ty.is_fresh()); // This check was an imperfect workaround for a bug in the old // intercrate mode; it should be removed when that goes away. if unbound_input_types && self.intercrate { @@ -1242,9 +1242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { - !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) - } + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_local_value(), _ => true, } } @@ -3048,20 +3046,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct<T>` -> `Struct<U>` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let fields = - def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); + let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { + GenericArgKind::Type(ty) => match ty.kind { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // Lifetimes aren't allowed to change during unsizing. + GenericArgKind::Lifetime(_) => None, + + GenericArgKind::Const(ct) => match ct.val { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, }; - let mut ty_params = GrowableBitSet::new_empty(); + + // The last field of the structure has to exist and contain type/const parameters. + let (tail_field, prefix_fields) = + def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; + let tail_field_ty = tcx.type_of(tail_field.did); + + let mut unsizing_params = GrowableBitSet::new_empty(); let mut found = false; - for ty in field.walk() { - if let ty::Param(p) = ty.kind { - ty_params.insert(p.index as usize); + for arg in tail_field_ty.walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); found = true; } } @@ -3069,31 +3078,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(Unimplemented); } - // Replace type parameters used in unsizing with - // Error and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let params = substs_a - .iter() - .enumerate() - .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); - let substs = tcx.mk_substs(params); - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, substs).references_error() { - return Err(Unimplemented); + // Ensure none of the other fields mention the parameters used + // in unsizing. + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + for field in prefix_fields { + for arg in tcx.type_of(field.did).walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + if unsizing_params.contains(i) { + return Err(Unimplemented); + } + } } } - // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`. + let source_tail = tail_field_ty.subst(tcx, substs_a); + let target_tail = tail_field_ty.subst(tcx, substs_b); // Check that the source struct with the target's - // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { - if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); - let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); + // unsizing parameters is equal to the target. + let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, &k)| { + if unsizing_params.contains(i as u32) { substs_b[i] } else { k } + })); + let new_struct = tcx.mk_adt(def, substs); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) @@ -3101,15 +3110,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `Field<T>: Unsize<Field<U>>` predicate. + // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. nested.push(predicate_for_trait_def( tcx, obligation.param_env, obligation.cause.clone(), obligation.predicate.def_id(), obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], + source_tail, + &[target_tail.into()], )); } @@ -3253,15 +3262,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( - |(obligation_ty, impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty + obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any( + |(obligation_arg, impl_arg)| { + match (obligation_arg.unpack(), impl_arg.unpack()) { + (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => { + let simplified_obligation_ty = + fast_reject::simplify_type(self.tcx(), obligation_ty, true); + let simplified_impl_ty = + fast_reject::simplify_type(self.tcx(), impl_ty, false); + + simplified_obligation_ty.is_some() + && simplified_impl_ty.is_some() + && simplified_obligation_ty != simplified_impl_ty + } + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => { + // Lifetimes can never cause a rejection. + false + } + (GenericArgKind::Const(_), GenericArgKind::Const(_)) => { + // Conservatively ignore consts (i.e. assume they might + // unify later) until we have `fast_reject` support for + // them (if we'll ever need it, even). + false + } + _ => unreachable!(), + } }, ) } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 1eb41e0b4d1..6b38749e1e7 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -4,7 +4,7 @@ use crate::traits::{self, AssocTypeBoundData}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; @@ -391,9 +391,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let mut subtys = ty0.walk(); + let mut walker = ty0.walk(); let param_env = self.param_env; - while let Some(ty) = subtys.next() { + while let Some(arg) = walker.next() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No WF constraints for lifetimes being present, any outlives + // obligations are handled by the parent (e.g. `ty::Ref`). + GenericArgKind::Lifetime(_) => continue, + + // FIXME(eddyb) this is wrong and needs to be replaced + // (see https://github.com/rust-lang/rust/pull/70107). + GenericArgKind::Const(_) => continue, + }; + match ty.kind { ty::Bool | ty::Char @@ -417,6 +429,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { ty::Array(subty, len) => { self.require_sized(subty, traits::SliceOrArrayElem); + // FIXME(eddyb) handle `GenericArgKind::Const` above instead. self.compute_array_len(*len); } @@ -433,7 +446,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::Projection(data) => { - subtys.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // subtree handled by compute_projection self.compute_projection(data); } @@ -504,7 +517,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // are not directly inspecting closure types // anyway, except via auto trait matching (which // only inspects the upvar types). - subtys.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // subtree handled by compute_projection for upvar_ty in substs.as_closure().upvar_tys() { self.compute(upvar_ty); } diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 28d5d25dd1b..612ab9b70eb 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -3,6 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::traits::{ Clause, Clauses, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory, }; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty, TyCtxt}; struct ClauseVisitor<'a, 'tcx> { @@ -210,7 +211,8 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { _ => NodeKind::Other, }; - let mut input_tys = FxHashSet::default(); + // FIXME(eddyb) isn't the unordered nature of this a hazard? + let mut inputs = FxHashSet::default(); match node_kind { // In a trait impl, we assume that the header trait ref and all its @@ -218,14 +220,14 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { NodeKind::TraitImpl => { let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); - input_tys.extend(trait_ref.input_types().flat_map(|ty| ty.walk())); + inputs.extend(trait_ref.substs.iter().flat_map(|&arg| arg.walk())); } // In an inherent impl, we assume that the receiver type and all its // constituents are well-formed. NodeKind::InherentImpl => { let self_ty = tcx.type_of(def_id); - input_tys.extend(self_ty.walk()); + inputs.extend(self_ty.walk()); } // In an fn, we assume that the arguments and all their constituents are @@ -234,16 +236,27 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { let fn_sig = tcx.fn_sig(def_id); let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); - input_tys.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); } NodeKind::Other => (), } let clauses = clauses.chain( - input_tys + inputs .into_iter() - .map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty))) + .filter_map(|arg| { + match arg.unpack() { + GenericArgKind::Type(ty) => Some(FromEnv::Ty(ty)), + + // FIXME(eddyb) no WF conditions from lifetimes? + GenericArgKind::Lifetime(_) => None, + + // FIXME(eddyb) support const generics in Chalk + GenericArgKind::Const(_) => None, + } + }) + .map(DomainGoal::FromEnv) .map(|domain_goal| domain_goal.into_program_clause()) .map(Clause::Implies), ); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c3ebcbfc832..ed7ec1c3b10 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -737,8 +737,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let default_needs_object_self = |param: &ty::GenericParamDef| { if let GenericParamDefKind::Type { has_default, .. } = param.kind { if is_object && has_default { + let default_ty = tcx.at(span).type_of(param.def_id); let self_param = tcx.types.self_param; - if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) { + if default_ty.walk().any(|arg| arg == self_param.into()) { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -1617,7 +1618,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Predicate::Projection(pred) => { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. - let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); + let references_self = + pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); // If the projection output contains `Self`, force the user to // elaborate it explicitly to avoid a lot of complexity. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5a97a2af120..ff3493eb6de 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -563,30 +563,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { while !queue.is_empty() { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => { - if unsize_did == tr.def_id() { - let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; - if let ty::Tuple(..) = sty { + let trait_pred = match obligation.predicate { + ty::Predicate::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { + if unsize_did == trait_pred.def_id() { + let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); + if let ty::Tuple(..) = unsize_ty.kind { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } } - *tr + trait_pred } _ => { coercion.obligations.push(obligation); continue; } }; - match selcx.select(&obligation.with(trait_ref)) { + match selcx.select(&obligation.with(trait_pred)) { // Uncertain or unimplemented. Ok(None) => { - if trait_ref.def_id() == unsize_did { - let trait_ref = self.resolve_vars_if_possible(&trait_ref); - let self_ty = trait_ref.skip_binder().self_ty(); - let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap(); - debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref); + if trait_pred.def_id() == unsize_did { + let trait_pred = self.resolve_vars_if_possible(&trait_pred); + let self_ty = trait_pred.skip_binder().self_ty(); + let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); match (&self_ty.kind, &unsize_ty.kind) { (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) if self.type_var_is_sized(*v) => diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 293c4feac62..eebc34d3db8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,6 +102,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items; use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; +use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -1767,7 +1768,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { let def_id = tcx.hir().local_def_id(it.hir_id); let pty_ty = tcx.type_of(def_id); let generics = tcx.generics_of(def_id); - check_bounds_are_used(tcx, &generics, pty_ty); + check_type_params_are_used(tcx, &generics, pty_ty); } hir::ItemKind::ForeignMod(ref m) => { check_abi(tcx, it.span, m.abi); @@ -4139,20 +4140,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `FulfillmentError`. let mut referenced_in = final_arg_types .iter() - .map(|(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty))) + .map(|&(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.resolve_vars_if_possible(&ty); // We walk the argument type because the argument's type could have // been `Option<T>`, but the `FulfillmentError` references `T`. - ty.walk() - .filter(|&ty| ty == predicate.skip_binder().self_ty()) - .map(move |_| *i) + if ty.walk().any(|arg| arg == predicate.skip_binder().self_ty().into()) { + Some(i) + } else { + None + } }) .collect::<Vec<_>>(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. + referenced_in.sort(); referenced_in.dedup(); if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { @@ -5744,43 +5748,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -pub fn check_bounds_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { - let own_counts = generics.own_counts(); - debug!( - "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})", - own_counts.types, own_counts.consts, ty - ); +fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { + debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + + assert_eq!(generics.parent, None); - if own_counts.types == 0 { + if generics.own_counts().types == 0 { return; } - // Make a vector of booleans initially `false`; set to `true` when used. - let mut types_used = vec![false; own_counts.types]; + let mut params_used = BitSet::new_empty(generics.params.len()); - for leaf_ty in ty.walk() { - if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.kind { - debug!("found use of ty param num {}", index); - types_used[index as usize - own_counts.lifetimes] = true; - } else if let ty::Error = leaf_ty.kind { - // If there is already another error, do not emit - // an error for not using a type parameter. - assert!(tcx.sess.has_errors()); - return; + if ty.references_error() { + // If there is already another error, do not emit + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); + return; + } + + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if let ty::Param(param) = leaf_ty.kind { + debug!("found use of ty param {:?}", param); + params_used.insert(param.index); + } } } - let types = generics.params.iter().filter(|param| match param.kind { - ty::GenericParamDefKind::Type { .. } => true, - _ => false, - }); - for (&used, param) in types_used.iter().zip(types) { - if !used { - let id = tcx.hir().as_local_hir_id(param.def_id).unwrap(); - let span = tcx.hir().span(id); - struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name) + for param in &generics.params { + if !params_used.contains(param.index) { + if let ty::GenericParamDefKind::Type { .. } = param.kind { + let span = tcx.def_span(param.def_id); + struct_span_err!( + tcx.sess, + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) .span_label(span, "unused type parameter") .emit(); + } } } } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index df7c535ff3b..2abca302469 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -119,7 +119,15 @@ fn insert_required_predicates_to_be_wf<'tcx>( required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for ty in field_ty.walk() { + for arg in field_ty.walk() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No predicates from lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + match ty.kind { // The field is of type &'a T which means that we will have // a predicate requirement of T: 'a (T outlives 'a). @@ -303,7 +311,7 @@ pub fn check_explicit_predicates<'tcx>( // 'b`. if let Some(self_ty) = ignored_self_ty { if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.walk().any(|ty| ty == self_ty) { + if ty.walk().any(|arg| arg == self_ty.into()) { debug!("skipping self ty = {:?}", &ty); continue; } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 73df844a91b..eb8aec708a6 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -315,25 +315,28 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> FxHashSet<GenericParamDef> { - pred.walk_tys() - .flat_map(|t| { - let mut regions = FxHashSet::default(); - tcx.collect_regions(&t, &mut regions); - - regions.into_iter().flat_map(|r| { - match r { - // We only care about late bound regions, as we need to add them - // to the 'for<>' section - &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => { - Some(GenericParamDef { - name: name.to_string(), - kind: GenericParamDefKind::Lifetime, - }) - } - &ty::ReVar(_) | &ty::ReEarlyBound(_) | &ty::ReStatic => None, - _ => panic!("Unexpected region type {:?}", r), - } - }) + let regions = match pred { + ty::Predicate::Trait(poly_trait_pred, _) => { + tcx.collect_referenced_late_bound_regions(&poly_trait_pred) + } + ty::Predicate::Projection(poly_proj_pred) => { + tcx.collect_referenced_late_bound_regions(&poly_proj_pred) + } + _ => return FxHashSet::default(), + }; + + regions + .into_iter() + .filter_map(|br| { + match br { + // We only care about named late bound regions, as we need to add them + // to the 'for<>' section + ty::BrNamed(_, name) => Some(GenericParamDef { + name: name.to_string(), + kind: GenericParamDefKind::Lifetime, + }), + _ => None, + } }) .collect() } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4111483902..5c35dc55132 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -84,15 +84,6 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> { } } -impl<T, U> Clean<U> for ty::Binder<T> -where - T: Clean<U>, -{ - fn clean(&self, cx: &DocContext<'_>) -> U { - self.skip_binder().clean(cx) - } -} - impl Clean<ExternalCrate> for CrateNum { fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate { let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; @@ -305,59 +296,66 @@ impl Clean<GenericBound> for hir::GenericBound<'_> { } } -impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) { - fn clean(&self, cx: &DocContext<'_>) -> GenericBound { - let (trait_ref, ref bounds) = *self; +impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &DocContext<'_>) -> Type { + let (trait_ref, bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); let path = external_path( cx, cx.tcx.item_name(trait_ref.def_id), Some(trait_ref.def_id), true, - bounds.clone(), + bounds.to_vec(), trait_ref.substs, ); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); + ResolvedPath { path, param_names: None, did: trait_ref.def_id, is_generic: false } + } +} + +impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { + GenericBound::TraitBound( + PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] }, + hir::TraitBoundModifier::None, + ) + } +} + +impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { + let (poly_trait_ref, bounds) = *self; + let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap(); + // collect any late bound regions - let mut late_bounds = vec![]; - for ty_s in trait_ref.input_types().skip(1) { - if let ty::Tuple(ts) = ty_s.kind { - for &ty_s in ts { - if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().kind { - if let &ty::RegionKind::ReLateBound(..) = *reg { - debug!(" hit an ReLateBound {:?}", reg); - if let Some(Lifetime(name)) = reg.clean(cx) { - late_bounds.push(GenericParamDef { - name, - kind: GenericParamDefKind::Lifetime, - }); - } - } - } - } - } - } + let late_bound_regions: Vec<_> = cx + .tcx + .collect_referenced_late_bound_regions(&poly_trait_ref) + .into_iter() + .filter_map(|br| match br { + ty::BrNamed(_, name) => Some(GenericParamDef { + name: name.to_string(), + kind: GenericParamDefKind::Lifetime, + }), + _ => None, + }) + .collect(); GenericBound::TraitBound( PolyTrait { - trait_: ResolvedPath { - path, - param_names: None, - did: trait_ref.def_id, - is_generic: false, - }, - generic_params: late_bounds, + trait_: (*poly_trait_ref.skip_binder(), bounds).clean(cx), + generic_params: late_bound_regions, }, hir::TraitBoundModifier::None, ) } } -impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> { +impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> GenericBound { - (self, vec![]).clean(cx) + (*self, &[][..]).clean(cx) } } @@ -495,16 +493,17 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> { } } -impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> { +impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { + let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); WherePredicate::BoundPredicate { - ty: self.trait_ref.self_ty().clean(cx), - bounds: vec![self.trait_ref.clean(cx)], + ty: poly_trait_ref.self_ty().clean(cx), + bounds: vec![poly_trait_ref.clean(cx)], } } } -impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> { +impl<'tcx> Clean<WherePredicate> for ty::PolySubtypePredicate<'tcx> { fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate { panic!( "subtype predicates are an internal rustc artifact \ @@ -514,10 +513,10 @@ impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> { } impl<'tcx> Clean<Option<WherePredicate>> - for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> + for ty::PolyOutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> { fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> { - let ty::OutlivesPredicate(ref a, ref b) = *self; + let ty::OutlivesPredicate(a, b) = self.skip_binder(); if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) { return None; @@ -530,9 +529,9 @@ impl<'tcx> Clean<Option<WherePredicate>> } } -impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> { +impl<'tcx> Clean<Option<WherePredicate>> for ty::PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> { fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> { - let ty::OutlivesPredicate(ref ty, ref lt) = *self; + let ty::OutlivesPredicate(ty, lt) = self.skip_binder(); if let ty::ReEmpty(_) = lt { return None; @@ -545,9 +544,10 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty: } } -impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> { +impl<'tcx> Clean<WherePredicate> for ty::PolyProjectionPredicate<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { - WherePredicate::EqPredicate { lhs: self.projection_ty.clean(cx), rhs: self.ty.clean(cx) } + let ty::ProjectionPredicate { projection_ty, ty } = *self.skip_binder(); + WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) } } } @@ -1674,7 +1674,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { } } - let bounds = bounds + let bounds: Vec<_> = bounds .predicates .iter() .filter_map(|pred| { @@ -1703,7 +1703,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { }) .collect(); - Some((trait_ref.skip_binder(), bounds).clean(cx)) + Some((trait_ref, &bounds[..]).clean(cx)) }) .collect::<Vec<_>>(); bounds.extend(regions); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 88d556229e4..5ab88260d6a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -261,6 +261,7 @@ use crate::cmp; use crate::fmt; +use crate::mem; use crate::memchr; use crate::ops::{Deref, DerefMut}; use crate::ptr; @@ -1376,6 +1377,70 @@ pub trait Write { Ok(()) } + /// Attempts to write multiple buffers into this writer. + /// + /// This method will continuously call [`write_vectored`] until there is no + /// more data to be written or an error of non-[`ErrorKind::Interrupted`] + /// kind is returned. This method will not return until all buffers have + /// been successfully written or such an error occurs. The first error that + /// is not of [`ErrorKind::Interrupted`] kind generated from this method + /// will be returned. + /// + /// If the buffer contains no data, this will never call [`write_vectored`]. + /// + /// [`write_vectored`]: #method.write_vectored + /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted + /// + /// # Notes + /// + /// + /// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to + /// a slice of `IoSlice`s, not an immutable one. That's because we need to + /// modify the slice to keep track of the bytes already written. + /// + /// Once this function returns, the contents of `bufs` are unspecified, as + /// this depends on how many calls to `write_vectored` were necessary. It is + /// best to understand this function as taking ownership of `bufs` and to + /// not use `bufs` afterwards. The underlying buffers, to which the + /// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and + /// can be reused. + /// + /// # Examples + /// + /// ``` + /// #![feature(write_all_vectored)] + /// # fn main() -> std::io::Result<()> { + /// + /// use std::io::{Write, IoSlice}; + /// + /// let mut writer = Vec::new(); + /// let bufs = &mut [ + /// IoSlice::new(&[1]), + /// IoSlice::new(&[2, 3]), + /// IoSlice::new(&[4, 5, 6]), + /// ]; + /// + /// writer.write_all_vectored(bufs)?; + /// // Note: the contents of `bufs` is now undefined, see the Notes section. + /// + /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]); + /// # Ok(()) } + /// ``` + #[unstable(feature = "write_all_vectored", issue = "70436")] + fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { + while !bufs.is_empty() { + match self.write_vectored(bufs) { + Ok(0) => { + return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")); + } + Ok(n) => bufs = IoSlice::advance(mem::take(&mut bufs), n), + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + /// Writes a formatted string into this writer, returning any error /// encountered. /// @@ -2423,7 +2488,7 @@ impl<B: BufRead> Iterator for Lines<B> { #[cfg(test)] mod tests { use super::{repeat, Cursor, SeekFrom}; - use crate::cmp; + use crate::cmp::{self, min}; use crate::io::prelude::*; use crate::io::{self, IoSlice, IoSliceMut}; use crate::ops::Deref; @@ -2812,4 +2877,107 @@ mod tests { bufs = IoSlice::advance(bufs, 9); assert!(bufs.is_empty()); } + + /// Create a new writer that reads from at most `n_bufs` and reads + /// `per_call` bytes (in total) per call to write. + fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { + TestWriter { n_bufs, per_call, written: Vec::new() } + } + + struct TestWriter { + n_bufs: usize, + per_call: usize, + written: Vec<u8>, + } + + impl Write for TestWriter { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + let mut left = self.per_call; + let mut written = 0; + for buf in bufs.iter().take(self.n_bufs) { + let n = min(left, buf.len()); + self.written.extend_from_slice(&buf[0..n]); + left -= n; + written += n; + } + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + #[test] + fn test_writer_read_from_one_buf() { + let mut writer = test_writer(1, 2); + + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + + // Read at most 2 bytes. + assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2); + let bufs = &[IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 2); + + // Only read from first buf. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 1); + + assert_eq!(writer.written, &[1, 1, 2, 2, 3]); + } + + #[test] + fn test_writer_read_from_multiple_bufs() { + let mut writer = test_writer(3, 3); + + // Read at most 3 bytes from two buffers. + let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + // Read at most 3 bytes from three buffers. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]); + } + + #[test] + fn test_write_all_vectored() { + #[rustfmt::skip] // Becomes unreadable otherwise. + let tests: Vec<(_, &'static [u8])> = vec![ + (vec![], &[]), + (vec![IoSlice::new(&[1])], &[1]), + (vec![IoSlice::new(&[1, 2])], &[1, 2]), + (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), + (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), + ]; + + let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]; + + for (n_bufs, per_call) in writer_configs.iter().copied() { + for (mut input, wanted) in tests.clone().into_iter() { + let mut writer = test_writer(n_bufs, per_call); + assert!(writer.write_all_vectored(&mut *input).is_ok()); + assert_eq!(&*writer.written, &*wanted); + } + } + } } diff --git a/src/llvm-project b/src/llvm-project -Subproject 130721d6f4e6cba3b910ccdf5e0aa62b9dffc95 +Subproject 027e428197f3702599cfbb632883768175f4917 diff --git a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs index 49b3abc99b7..bc1e18b657f 100644 --- a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs +++ b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs @@ -8,8 +8,8 @@ extern crate coherence_lib as lib; use lib::*; #[fundamental] -struct Local; +struct Local<T>(T); -impl Remote for Local {} +impl Remote for Local<()> {} fn main() {} diff --git a/src/test/ui/consts/const-eval/issue-70723.rs b/src/test/ui/consts/const-eval/issue-70723.rs new file mode 100644 index 00000000000..8b79d5d53c5 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-70723.rs @@ -0,0 +1,5 @@ +#![feature(const_loop)] + +static _X: () = loop {}; //~ ERROR could not evaluate static initializer + +fn main() {} diff --git a/src/test/ui/consts/const-eval/issue-70723.stderr b/src/test/ui/consts/const-eval/issue-70723.stderr new file mode 100644 index 00000000000..687d6565a71 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-70723.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/issue-70723.rs:3:17 + | +LL | static _X: () = loop {}; + | ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.stderr b/src/test/ui/impl-trait/does-not-live-long-enough.stderr index 83d0f87015b..9cff4bcd8b5 100644 --- a/src/test/ui/impl-trait/does-not-live-long-enough.stderr +++ b/src/test/ui/impl-trait/does-not-live-long-enough.stderr @@ -14,7 +14,7 @@ LL | } help: you can add a bound to the opaque type to make it last less than `'static` and match `'a` | LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/layout/debug.rs b/src/test/ui/layout/debug.rs index 034ed3190c1..299151df664 100644 --- a/src/test/ui/layout/debug.rs +++ b/src/test/ui/layout/debug.rs @@ -3,19 +3,19 @@ #![crate_type = "lib"] #[rustc_layout(debug)] -enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout debugging +enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of #[rustc_layout(debug)] -struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout debugging +struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout_of #[rustc_layout(debug)] -union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout debugging +union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout_of #[rustc_layout(debug)] -type Test = Result<i32, i32>; //~ ERROR: layout debugging +type Test = Result<i32, i32>; //~ ERROR: layout_of #[rustc_layout(debug)] -type T = impl std::fmt::Debug; //~ ERROR: layout debugging +type T = impl std::fmt::Debug; //~ ERROR: layout_of fn f() -> T { 0i32 diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr index 3539cea5ea3..153dec594d3 100644 --- a/src/test/ui/layout/debug.stderr +++ b/src/test/ui/layout/debug.stderr @@ -1,4 +1,4 @@ -error: layout debugging for type E: Layout { +error: layout_of(E) = Layout { fields: Arbitrary { offsets: [ Size { @@ -110,7 +110,7 @@ error: layout debugging for type E: Layout { LL | enum E { Foo, Bar(!, i32, i32) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: layout debugging for type S: Layout { +error: layout_of(S) = Layout { fields: Arbitrary { offsets: [ Size { @@ -164,7 +164,7 @@ error: layout debugging for type S: Layout { LL | struct S { f1: i32, f2: (), f3: i32 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: layout debugging for type U: Layout { +error: layout_of(U) = Layout { fields: Union( 2, ), @@ -190,7 +190,7 @@ error: layout debugging for type U: Layout { LL | union U { f1: (i32, i32), f3: i32 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: layout debugging for type std::result::Result<i32, i32>: Layout { +error: layout_of(std::result::Result<i32, i32>) = Layout { fields: Arbitrary { offsets: [ Size { @@ -315,7 +315,7 @@ error: layout debugging for type std::result::Result<i32, i32>: Layout { LL | type Test = Result<i32, i32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: layout debugging for type i32: Layout { +error: layout_of(i32) = Layout { fields: Union( 0, ), diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr index 742f4fdc38b..bc61b3b74e2 100644 --- a/src/test/ui/parser/issue-32214.stderr +++ b/src/test/ui/parser/issue-32214.stderr @@ -4,7 +4,12 @@ error: generic arguments must come before the first constraint LL | pub fn test<W, I: Trait<Item=(), W> >() {} | ------- ^ generic argument | | - | the first constraint is provided here + | constraint + | +help: move the constraint after the generic argument + | +LL | pub fn test<W, I: Trait<W, Item = ()> >() {} + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs new file mode 100644 index 00000000000..cc36f054bc3 --- /dev/null +++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs @@ -0,0 +1,20 @@ +// edition:2018 + +async fn free(); //~ ERROR without a body + +struct A; +impl A { + async fn inherent(); //~ ERROR without body +} + +trait B { + async fn associated(); + //~^ ERROR cannot be declared `async` +} +impl B for A { + async fn associated(); //~ ERROR without body + //~^ ERROR cannot be declared `async` + //~| ERROR incompatible type for trait +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr new file mode 100644 index 00000000000..a324d04d394 --- /dev/null +++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr @@ -0,0 +1,65 @@ +error: free function without a body + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:3:1 + | +LL | async fn free(); + | ^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error: associated function in `impl` without body + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:7:5 + | +LL | async fn inherent(); + | ^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5 + | +LL | async fn associated(); + | -----^^^^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error: associated function in `impl` without body + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5 + | +LL | async fn associated(); + | ^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5 + | +LL | async fn associated(); + | -----^^^^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0053]: method `associated` has an incompatible type for trait + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26 + | +LL | async fn associated(); + | - type in trait +... +LL | async fn associated(); + | ^ + | | + | the `Output` of this `async fn`'s found opaque type + | expected `()`, found opaque type + | + = note: expected fn pointer `fn()` + found fn pointer `fn() -> impl std::future::Future` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0053, E0706. +For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/sanitize-inline-always.rs b/src/test/ui/sanitize/inline-always.rs index 52dc5578180..52dc5578180 100644 --- a/src/test/ui/sanitize-inline-always.rs +++ b/src/test/ui/sanitize/inline-always.rs diff --git a/src/test/ui/sanitize-inline-always.stderr b/src/test/ui/sanitize/inline-always.stderr index 50b9474baa2..84c05af4cf8 100644 --- a/src/test/ui/sanitize-inline-always.stderr +++ b/src/test/ui/sanitize/inline-always.stderr @@ -1,12 +1,12 @@ warning: `no_sanitize` will have no effect after inlining - --> $DIR/sanitize-inline-always.rs:7:1 + --> $DIR/inline-always.rs:7:1 | LL | #[no_sanitize(address)] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(inline_no_sanitize)]` on by default note: inlining requested here - --> $DIR/sanitize-inline-always.rs:5:1 + --> $DIR/inline-always.rs:5:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 4dd0613757a..3bb6fd6e4f4 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -4,79 +4,103 @@ error: generic arguments must come before the first constraint LL | struct A<T, M: One<A=(), T>> { | ---- ^ generic argument | | - | the first constraint is provided here + | constraint + | +help: move the constraint after the generic argument + | +LL | struct A<T, M: One<T, A = ()>> { + | ^^^^^^^^^^^ error: generic arguments must come before the first constraint --> $DIR/suggest-move-types.rs:33:43 | LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> { - | ---- ^ ^^ generic argument - | | | - | | generic argument - | the first constraint is provided here + | ---- ^ ^^ generic arguments + | | + | constraint + | +help: move the constraint after the generic arguments + | +LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A = ()>> { + | ^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint --> $DIR/suggest-move-types.rs:40:46 | LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { - | ---- ^ ^ ^ generic argument - | | | | - | | | generic argument - | | generic argument - | the first constraint is provided here + | ---- ---- ---- ^ ^ ^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct B<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> { - | ---- ^ ^ ^ ^^ ^^ ^^ generic argument - | | | | | | | - | | | | | | generic argument - | | | | | generic argument - | | | | generic argument - | | | generic argument - | | generic argument - | the first constraint is provided here + | ---- ---- ---- ^ ^ ^ ^^ ^^ ^^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint - --> $DIR/suggest-move-types.rs:57:49 + --> $DIR/suggest-move-types.rs:57:28 | LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { - | ---- ^ ^ generic argument - | | | - | | generic argument - | the first constraint is provided here + | ^ ---- ---- ---- ^ ^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct C<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint - --> $DIR/suggest-move-types.rs:65:78 + --> $DIR/suggest-move-types.rs:65:53 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> { - | ---- ^ ^^ ^ ^^ generic argument - | | | | | - | | | | generic argument - | | | generic argument - | | generic argument - | the first constraint is provided here + | ^ ^^ ---- ---- ---- ^ ^^ ^ ^^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint - --> $DIR/suggest-move-types.rs:74:43 + --> $DIR/suggest-move-types.rs:74:28 | LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { - | ---- ^ ^ generic argument - | | | - | | generic argument - | the first constraint is provided here + | ^ ---- ---- ^ ---- ^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct D<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: generic arguments must come before the first constraint - --> $DIR/suggest-move-types.rs:82:72 + --> $DIR/suggest-move-types.rs:82:53 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> { - | ---- ^ ^^ ^ ^^ generic argument - | | | | | - | | | | generic argument - | | | generic argument - | | generic argument - | the first constraint is provided here + | ^ ^^ ---- ---- ^ ^^ ---- ^ ^^ generic arguments + | | + | constraints + | +help: move the constraints after the generic arguments + | +LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0747]: type provided when a lifetime was expected --> $DIR/suggest-move-types.rs:33:43 |
