diff options
Diffstat (limited to 'compiler')
224 files changed, 2964 insertions, 1902 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3e953729aab..328086af183 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1192,6 +1192,7 @@ impl Expr { ExprKind::Field(..) => ExprPrecedence::Field, ExprKind::Index(..) => ExprPrecedence::Index, ExprKind::Range(..) => ExprPrecedence::Range, + ExprKind::Underscore => ExprPrecedence::Path, ExprKind::Path(..) => ExprPrecedence::Path, ExprKind::AddrOf(..) => ExprPrecedence::AddrOf, ExprKind::Break(..) => ExprPrecedence::Break, @@ -1324,6 +1325,8 @@ pub enum ExprKind { Index(P<Expr>, P<Expr>), /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment). Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits), + /// An underscore, used in destructuring assignment to ignore a value. + Underscore, /// Variable reference, possibly containing `::` and/or type /// parameters (e.g., `foo::bar::<baz>`). diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 26097980e8b..ddae0ab03e4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1232,6 +1232,7 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(e1, |e1| vis.visit_expr(e1)); visit_opt(e2, |e2| vis.visit_expr(e2)); } + ExprKind::Underscore => {} ExprKind::Path(qself, path) => { vis.visit_qself(qself); vis.visit_path(path); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 49b521afcdc..560064182e1 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -806,6 +806,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_expr, start); walk_list!(visitor, visit_expr, end); } + ExprKind::Underscore => {} ExprKind::Path(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { visitor.visit_ty(&qself.ty); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b94fb1d8437..f83fc29577b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -164,6 +164,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Range(ref e1, ref e2, lims) => { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } + ExprKind::Underscore => { + self.sess + .struct_span_err( + e.span, + "in expressions, `_` can only be used on the left-hand side of an assignment", + ) + .span_label(e.span, "`_` not allowed here") + .emit(); + hir::ExprKind::Err + } ExprKind::Path(ref qself, ref path) => { let qpath = self.lower_qpath( e.id, @@ -863,7 +873,10 @@ impl<'hir> LoweringContext<'_, 'hir> { // Return early in case of an ordinary assignment. fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool { match &lhs.kind { - ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false, + ExprKind::Array(..) + | ExprKind::Struct(..) + | ExprKind::Tup(..) + | ExprKind::Underscore => false, // Check for tuple struct constructor. ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(), ExprKind::Paren(e) => { @@ -943,6 +956,10 @@ impl<'hir> LoweringContext<'_, 'hir> { assignments: &mut Vec<hir::Stmt<'hir>>, ) -> &'hir hir::Pat<'hir> { match &lhs.kind { + // Underscore pattern. + ExprKind::Underscore => { + return self.pat_without_dbm(lhs.span, hir::PatKind::Wild); + } // Slice patterns. ExprKind::Array(elements) => { let (pats, rest) = diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 88ad2706eac..d93655e5905 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::config::nightly_options; use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::ParseSess; use rustc_session::Session; @@ -1398,8 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { "`impl Trait` not allowed outside of {}", allowed_in, ); - if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build() - { + if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() { err.help( "add `#![feature(impl_trait_in_bindings)]` to the crate \ attributes to enable", diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2831675cb36..181783441f3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -630,7 +630,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(inline_const, "inline-const is experimental"); - gate_all!(destructuring_assignment, "destructuring assignments are unstable"); + if sess.parse_sess.span_diagnostic.err_count() == 0 { + // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is + // involved, so we only emit errors where there are no other parsing errors. + gate_all!(destructuring_assignment, "destructuring assignments are unstable"); + } // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 958219cbebf..fdb129d9e2a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -109,7 +109,6 @@ pub fn print_crate<'a>( ann: &'a dyn PpAnn, is_expanded: bool, edition: Edition, - has_injected_crate: bool, ) -> String { let mut s = State { s: pp::mk_printer(), @@ -119,7 +118,7 @@ pub fn print_crate<'a>( insert_extra_parens: true, }; - if is_expanded && has_injected_crate { + if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However, we don't want these attributes in the AST because @@ -2068,6 +2067,7 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(e, fake_prec); } } + ast::ExprKind::Underscore => self.s.word("_"), ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0), ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true), ast::ExprKind::Break(opt_label, ref opt_expr) => { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e801b5c7b0c..91566ec1ef2 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -13,12 +13,12 @@ pub fn inject( resolver: &mut dyn ResolverExpand, sess: &Session, alt_std_name: Option<Symbol>, -) -> (ast::Crate, Option<Symbol>) { +) -> ast::Crate { let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return (krate, None); + return krate; } else if sess.contains_name(&krate.attrs, sym::no_std) { if sess.contains_name(&krate.attrs, sym::compiler_builtins) { &[sym::core] @@ -81,5 +81,5 @@ pub fn inject( krate.module.items.insert(0, use_item); - (krate, Some(name)) + krate } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 81091728692..ac076789f2e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -216,7 +216,7 @@ pub(crate) fn get_function_name_and_sig<'tcx>( assert!(!inst.substs.needs_infer()); let fn_sig = tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &fn_sig_for_fn_abi(tcx, inst), + fn_sig_for_fn_abi(tcx, inst), ); if fn_sig.c_variadic && !support_vararg { tcx.sess.span_fatal( @@ -372,7 +372,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>( .mir .args_iter() .map(|local| { - let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty); + let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty); // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482 if Some(local) == fx.mir.spread_arg { @@ -470,7 +470,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>( } for local in fx.mir.vars_and_temps_iter() { - let ty = fx.monomorphize(&fx.mir.local_decls[local].ty); + let ty = fx.monomorphize(fx.mir.local_decls[local].ty); let layout = fx.layout_of(ty); let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa; @@ -492,10 +492,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( args: &[Operand<'tcx>], destination: Option<(Place<'tcx>, BasicBlock)>, ) { - let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx)); + let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); let fn_sig = fx .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx)); + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); let destination = destination.map(|(place, bb)| (codegen_place(fx, place), bb)); @@ -711,7 +711,7 @@ pub(crate) fn codegen_drop<'tcx>( let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all()); let fn_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &drop_fn_ty.fn_sig(fx.tcx), + drop_fn_ty.fn_sig(fx.tcx), ); assert_eq!(fn_sig.output(), fx.tcx.mk_unit()); diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index fd25b19a583..adf5c7ac4fe 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -17,7 +17,7 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Module>) -> IndexVec<Local, S .local_decls .iter() .map(|local_decl| { - let ty = fx.monomorphize(&local_decl.ty); + let ty = fx.monomorphize(local_decl.ty); if fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some() { SsaKind::Ssa } else { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index bfe5514b6d3..a4df371c88a 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -445,43 +445,43 @@ fn codegen_stmt<'tcx>( StatementKind::Assign(to_place_and_rval) => { let lval = codegen_place(fx, to_place_and_rval.0); let dest_layout = lval.layout(); - match &to_place_and_rval.1 { - Rvalue::Use(operand) => { + match to_place_and_rval.1 { + Rvalue::Use(ref operand) => { let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let ref_ = place.place_ref(fx, lval.layout()); lval.write_cvalue(fx, ref_); } Rvalue::ThreadLocalRef(def_id) => { - let val = crate::constant::codegen_tls_ref(fx, *def_id, lval.layout()); + let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout()); lval.write_cvalue(fx, val); } - Rvalue::BinaryOp(bin_op, lhs, rhs) => { + Rvalue::BinaryOp(bin_op, ref lhs, ref rhs) => { let lhs = codegen_operand(fx, lhs); let rhs = codegen_operand(fx, rhs); - let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs); + let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs); lval.write_cvalue(fx, res); } - Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => { + Rvalue::CheckedBinaryOp(bin_op, ref lhs, ref rhs) => { let lhs = codegen_operand(fx, lhs); let rhs = codegen_operand(fx, rhs); let res = if !fx.tcx.sess.overflow_checks() { let val = - crate::num::codegen_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx); + crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx); let is_overflow = fx.bcx.ins().iconst(types::I8, 0); CValue::by_val_pair(val, is_overflow, lval.layout()) } else { - crate::num::codegen_checked_int_binop(fx, *bin_op, lhs, rhs) + crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs) }; lval.write_cvalue(fx, res); } - Rvalue::UnaryOp(un_op, operand) => { + Rvalue::UnaryOp(un_op, ref operand) => { let operand = codegen_operand(fx, operand); let layout = operand.layout(); let val = operand.load_scalar(fx); @@ -509,8 +509,8 @@ fn codegen_stmt<'tcx>( }; lval.write_cvalue(fx, res); } - Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), operand, to_ty) => { - let from_ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx)); + Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), ref operand, to_ty) => { + let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx)); let to_layout = fx.layout_of(fx.monomorphize(to_ty)); match *from_ty.kind() { ty::FnDef(def_id, substs) => { @@ -530,14 +530,14 @@ fn codegen_stmt<'tcx>( _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => { + Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), ref operand, to_ty) + | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), ref operand, to_ty) + | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), ref operand, to_ty) => { let to_layout = fx.layout_of(fx.monomorphize(to_ty)); let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } - Rvalue::Cast(CastKind::Misc, operand, to_ty) => { + Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => { let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); @@ -577,12 +577,12 @@ fn codegen_stmt<'tcx>( use rustc_target::abi::{Int, TagEncoding, Variants}; - match &operand.layout().variants { + match operand.layout().variants { Variants::Single { index } => { let discr = operand .layout() .ty - .discriminant_for_variant(fx.tcx, *index) + .discriminant_for_variant(fx.tcx, index) .unwrap(); let discr = if discr.ty.is_signed() { fx.layout_of(discr.ty).size.sign_extend(discr.val) @@ -595,7 +595,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, discr); } Variants::Multiple { - tag, + ref tag, tag_field, tag_encoding: TagEncoding::Direct, variants: _, @@ -604,7 +604,7 @@ fn codegen_stmt<'tcx>( // Read the tag/niche-encoded discriminant from memory. let encoded_discr = - operand.value_field(fx, mir::Field::new(*tag_field)); + operand.value_field(fx, mir::Field::new(tag_field)); let encoded_discr = encoded_discr.load_scalar(fx); // Decode the discriminant (specifically if it's niche-encoded). @@ -634,7 +634,7 @@ fn codegen_stmt<'tcx>( } Rvalue::Cast( CastKind::Pointer(PointerCast::ClosureFnPointer(_)), - operand, + ref operand, _to_ty, ) => { let operand = codegen_operand(fx, operand); @@ -654,18 +654,18 @@ fn codegen_stmt<'tcx>( _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _to_ty) => { + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => { let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } Rvalue::Discriminant(place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let value = place.to_cvalue(fx); let discr = crate::discriminant::codegen_get_discriminant(fx, value, dest_layout); lval.write_cvalue(fx, discr); } - Rvalue::Repeat(operand, times) => { + Rvalue::Repeat(ref operand, times) => { let operand = codegen_operand(fx, operand); let times = fx .monomorphize(times) @@ -704,7 +704,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Len(place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let usize_layout = fx.layout_of(fx.tcx.types.usize); let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); @@ -749,7 +749,7 @@ fn codegen_stmt<'tcx>( CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into()); lval.write_cvalue(fx, val); } - Rvalue::Aggregate(kind, operands) => match **kind { + Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() { AggregateKind::Array(_ty) => { for (i, operand) in operands.iter().enumerate() { let operand = codegen_operand(fx, operand); @@ -877,8 +877,7 @@ fn codegen_array_len<'tcx>( match *place.layout().ty.kind() { ty::Array(_elem_ty, len) => { let len = fx - .monomorphize(&len) - .eval(fx.tcx, ParamEnv::reveal_all()) + .monomorphize(len) .eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64; fx.bcx.ins().iconst(fx.pointer_type, len) } diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 466758f2f86..d7d6c3e1677 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -357,7 +357,7 @@ impl<'tcx, M: Module> HasTargetSpec for FunctionCx<'_, 'tcx, M> { } impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { - pub(crate) fn monomorphize<T>(&self, value: &T) -> T + pub(crate) fn monomorphize<T>(&self, value: T) -> T where T: TypeFoldable<'tcx> + Copy, { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 41cfae4ca6e..351bb6ecd23 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -38,7 +38,7 @@ impl ConstantCx { pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, impl Module>) { for constant in &fx.mir.required_consts { - let const_ = fx.monomorphize(&constant.literal); + let const_ = fx.monomorphize(constant.literal); match const_.val { ConstKind::Value(_) => {} ConstKind::Unevaluated(def, ref substs, promoted) => { @@ -110,7 +110,7 @@ pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let const_ = fx.monomorphize(&constant.literal); + let const_ = fx.monomorphize(constant.literal); let const_val = match const_.val { ConstKind::Value(const_val) => const_val, ConstKind::Unevaluated(def, ref substs, promoted) if fx.tcx.is_static(def.did) => { @@ -466,7 +466,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match operand { Operand::Copy(_) | Operand::Move(_) => None, Operand::Constant(const_) => Some( - fx.monomorphize(&const_.literal) + fx.monomorphize(const_.literal) .eval(fx.tcx, ParamEnv::reveal_all()), ), } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 85e8158af27..a6f4ded41b6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -365,7 +365,7 @@ impl<'tcx> DebugContext<'tcx> { let ty = self.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &mir.local_decls[local].ty, + mir.local_decls[local].ty, ); let var_id = self.define_local(entry_id, format!("{:?}", local), ty); diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 10f515e38ea..6c472e6774f 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -50,7 +50,7 @@ pub(crate) fn maybe_create_entry_wrapper( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); let cmain_sig = Signature { params: vec![ diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index ff878af7f5e..a9f060e51d8 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -80,7 +80,7 @@ impl CommentWriter { "sig {:?}", tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &crate::abi::fn_sig_for_fn_abi(tcx, instance) + crate::abi::fn_sig_for_fn_abi(tcx, instance) ) ), String::new(), diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 0000866c4f6..cb40d4ed9a6 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -455,7 +455,7 @@ impl<'tcx> CPlace<'tcx> { from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) { - match (&from_ty.kind(), &to_ty.kind()) { + match (from_ty.kind(), to_ty.kind()) { (ty::Ref(_, a, _), ty::Ref(_, b, _)) | ( ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), @@ -466,11 +466,11 @@ impl<'tcx> CPlace<'tcx> { (ty::FnPtr(_), ty::FnPtr(_)) => { let from_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &from_ty.fn_sig(fx.tcx), + from_ty.fn_sig(fx.tcx), ); let to_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &to_ty.fn_sig(fx.tcx), + to_ty.fn_sig(fx.tcx), ); assert_eq!( from_sig, to_sig, @@ -479,7 +479,7 @@ impl<'tcx> CPlace<'tcx> { ); // fn(&T) -> for<'l> fn(&'l T) is allowed } - (ty::Dynamic(from_traits, _), ty::Dynamic(to_traits, _)) => { + (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { let from_traits = fx .tcx .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index e06e2d45665..9a2fbf359ea 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -25,7 +25,7 @@ use crate::value::Value; /// Mark LLVM function to use provided inline heuristic. #[inline] -fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { +fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires_inline: bool) { use self::InlineAttr::*; match inline { Hint => Attribute::InlineHint.apply_llfn(Function, val), @@ -35,11 +35,8 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { Attribute::NoInline.apply_llfn(Function, val); } } - None => { - Attribute::InlineHint.unapply_llfn(Function, val); - Attribute::AlwaysInline.unapply_llfn(Function, val); - Attribute::NoInline.unapply_llfn(Function, val); - } + None if requires_inline => Attribute::InlineHint.apply_llfn(Function, val), + None => {} }; } @@ -229,12 +226,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: } } - // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). - if instance.def.requires_inline(cx.tcx) { - inline(cx, llfn, attributes::InlineAttr::Hint); - } - - inline(cx, llfn, codegen_fn_attrs.inline.clone()); + inline(cx, llfn, codegen_fn_attrs.inline.clone(), instance.def.requires_inline(cx.tcx)); // The `uwtable` attribute according to LLVM is: // diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 1090d4a25c7..7d01f6a5499 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -97,14 +97,12 @@ pub fn compile_codegen_unit( tcx: TyCtxt<'tcx>, cgu_name: Symbol, ) -> (ModuleCodegen<ModuleLlvm>, u64) { - let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string()); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); let time_to_codegen = start_time.elapsed(); - drop(prof_timer); // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. @@ -112,6 +110,10 @@ pub fn compile_codegen_unit( fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> { let cgu = tcx.codegen_unit(cgu_name); + let _prof_timer = tcx.prof.generic_activity_with_args( + "codegen_module", + &[cgu_name.to_string(), cgu.size_estimate().to_string()], + ); // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 6737872f203..7673dfb744c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -92,7 +92,7 @@ fn make_mir_scope( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &callee, + callee, ); let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]); cx.dbg_scope_fn(callee, &callee_fn_abi, None) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 27b81ebcff6..5e8ff14f0aa 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -189,7 +189,7 @@ impl TypeMap<'ll, 'tcx> { // something that provides more than the 64 bits of the DefaultHasher. let mut hasher = StableHasher::new(); let mut hcx = cx.tcx.create_stable_hashing_context(); - let type_ = cx.tcx.erase_regions(&type_); + let type_ = cx.tcx.erase_regions(type_); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_.hash_stable(hcx, &mut hasher); @@ -427,7 +427,7 @@ fn subroutine_type_metadata( span: Span, ) -> MetadataCreationResult<'ll> { let signature = - cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &signature); + cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature); let signature_metadata: Vec<_> = iter::once( // return type diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 5065ff01aed..ccbe7325cc6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -501,7 +501,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &cx.tcx.type_of(impl_def_id), + cx.tcx.type_of(impl_def_id), ); // Only "class" methods are generally understood by LLVM, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d52b3be8cd3..ac423d01bf1 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -91,7 +91,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { }; let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); @@ -777,8 +777,8 @@ fn generic_simd_intrinsic( } let tcx = bx.tcx(); - let sig = tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &callee_ty.fn_sig(tcx)); + let sig = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); let name_str = &*name.as_str(); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index cc71b6289fa..a3139ce5a34 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -3,7 +3,6 @@ use crate::llvm; use libc::c_int; use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxHashSet; -use rustc_feature::UnstableFeatures; use rustc_middle::bug; use rustc_session::config::PrintRequest; use rustc_session::Session; @@ -130,6 +129,13 @@ pub fn time_trace_profiler_finish(file_name: &str) { // WARNING: the features after applying `to_llvm_feature` must be known // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. +// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def +// where the * matches the architecture's name +// Beware to not use the llvm github project for this, but check the git submodule +// found in src/llvm-project +// Though note that Rust can also be build with an external precompiled version of LLVM +// which might lead to failures if the oldest tested / supported LLVM version +// doesn't yet support the relevant intrinsics pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { @@ -137,6 +143,9 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "rdrand") => "rdrnd", ("x86", "bmi1") => "bmi", ("x86", "cmpxchg16b") => "cx16", + ("x86", "avx512vaes") => "vaes", + ("x86", "avx512gfni") => "gfni", + ("x86", "avx512vpclmulqdq") => "vpclmulqdq", ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", (_, s) => s, @@ -147,13 +156,11 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> { let target_machine = create_informational_target_machine(sess); supported_target_features(sess) .iter() - .filter_map(|&(feature, gate)| { - if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { - Some(feature) - } else { - None - } - }) + .filter_map( + |&(feature, gate)| { + if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + }, + ) .filter(|feature| { let llvm_feature = to_llvm_feature(sess, feature); let cstr = CString::new(llvm_feature).unwrap(); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e0754d21df1..8ea4768f77d 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -252,7 +252,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(&self.ty); + let normal_ty = cx.tcx.erase_regions(self.ty); let mut defer = None; let llty = if self.ty != normal_ty { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 5fe26dbf914..21138f967a2 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -399,7 +399,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap()); let llfn = match cx.declare_c_main(llfty) { Some(llfn) => llfn, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 0b49a379070..896af8a9191 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -120,8 +120,8 @@ pub fn push_debuginfo_type_name<'tcx>( } ty::Dynamic(ref trait_data, ..) => { if let Some(principal) = trait_data.principal() { - let principal = tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal); + let principal = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); push_item_name(tcx, principal.def_id, false, output); push_type_params(tcx, principal.substs, output, visited); } else { @@ -159,7 +159,7 @@ pub fn push_debuginfo_type_name<'tcx>( output.push_str("fn("); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { push_debuginfo_type_name(tcx, parameter_type, true, output, visited); diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index bdde07d3fa9..44bb0deeae9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -24,7 +24,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( analyzer.visit_body(&mir); for (local, decl) in mir.local_decls.iter_enumerated() { - let ty = fx.monomorphize(&decl.ty); + let ty = fx.monomorphize(decl.ty); debug!("local {:?} has type `{}`", local, ty); let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); if fx.cx.is_backend_immediate(layout) { @@ -121,10 +121,10 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { if is_consume { let base_ty = mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(&base_ty); + let base_ty = self.fx.monomorphize(base_ty); // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty; + let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty; let span = self.fx.mir.local_decls[place_ref.local].source_info.span; if cx.spanned_layout_of(elem_ty, span).is_zst() { return; @@ -313,7 +313,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::MutatingUse(MutatingUseContext::Drop) => { let ty = self.fx.mir.local_decls[local].ty; - let ty = self.fx.monomorphize(&ty); + let ty = self.fx.monomorphize(ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index da4637b1afc..ee40095883d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -306,7 +306,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind: Option<mir::BasicBlock>, ) { let ty = location.ty(self.mir, bx.tcx()).ty; - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { @@ -576,7 +576,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .iter() .map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); - self.monomorphize(&op_ty) + self.monomorphize(op_ty) }) .collect::<Vec<_>>(); @@ -900,7 +900,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::InlineAsmOperand::SymFn { ref value } => { - let literal = self.monomorphize(&value.literal); + let literal = self.monomorphize(value.literal); if let ty::FnDef(def_id, substs) = *literal.ty.kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 4943e279c7e..c8001b8daf0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -16,7 +16,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> { let val = self.eval_mir_constant(constant)?; - let ty = self.monomorphize(&constant.literal.ty); + let ty = self.monomorphize(constant.literal.ty); Ok(OperandRef::from_const(bx, val, ty)) } @@ -24,7 +24,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, constant: &mir::Constant<'tcx>, ) -> Result<ConstValue<'tcx>, ErrorHandled> { - match self.monomorphize(&constant.literal).val { + match self.monomorphize(constant.literal).val { ty::ConstKind::Unevaluated(def, substs, promoted) => self .cx .tcx() @@ -83,7 +83,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .unwrap_or_else(|_| { bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time"); // We've errored, so we don't have to produce working code. - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); let llty = bx.backend_type(bx.layout_of(ty)); (bx.const_undef(llty), ty) }) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 4e0396a15a6..c4191a4e23d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) is this `+ 1` needed at all? let kind = VariableKind::ArgumentVariable(arg_index + 1); - let arg_ty = self.monomorphize(&decl.ty); + let arg_ty = self.monomorphize(decl.ty); self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) }, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 2bf1ee43c73..94340e92048 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let sig = callee_ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = bx.tcx().item_name(def_id); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 01fd1681593..640f805d5e8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -87,7 +87,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn monomorphize<T>(&self, value: &T) -> T + pub fn monomorphize<T>(&self, value: T) -> T where T: Copy + TypeFoldable<'tcx>, { @@ -208,7 +208,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut allocate_local = |local| { let decl = &mir.local_decls[local]; - let layout = bx.layout_of(fx.monomorphize(&decl.ty)); + let layout = bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { @@ -364,7 +364,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // to reconstruct it into a tuple local variable, from multiple // individual LLVM function arguments. - let arg_ty = fx.monomorphize(&arg_decl.ty); + let arg_ty = fx.monomorphize(arg_decl.ty); let tupled_arg_tys = match arg_ty.kind() { ty::Tuple(tys) => tys, _ => bug!("spread argument isn't a tuple?!"), @@ -385,7 +385,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { - let arg_ty = fx.monomorphize(&arg_decl.ty); + let arg_ty = fx.monomorphize(arg_decl.ty); let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); bx.va_start(va_list.llval); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index bbd004be875..08a4ae3962b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.abort(); // We still have to return an operand but it doesn't matter, // this code is unreachable. - let ty = self.monomorphize(&constant.literal.ty); + let ty = self.monomorphize(constant.literal.ty); let layout = bx.cx().layout_of(ty); bx.load_operand(PlaceRef::new_sized( bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index e1cc0268723..e4f4c884470 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base.project_index(bx, bx.cx().const_usize(from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty; - subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); + subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); if subslice.layout.is_unsized() { assert!(from_end, "slice subslices should be `from_end`"); @@ -515,6 +515,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, self.mir, tcx); - self.monomorphize(&place_ty.ty) + self.monomorphize(place_ty.ty) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 40ae0a13c72..2ad470c2693 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let count = - self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); + self.monomorphize(count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); bx.write_operand_repeatedly(cg_elem, count, dest) } @@ -181,7 +181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { let operand = self.codegen_operand(&mut bx, source); debug!("cast operand is {:?}", operand); - let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty)); + let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { @@ -502,7 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes()); let tcx = self.cx.tcx(); @@ -516,7 +516,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty = self.monomorphize(&content_ty); + let content_ty = self.monomorphize(content_ty); let content_layout = bx.cx().layout_of(content_ty); let llsize = bx.cx().const_usize(content_layout.size.bytes()); let llalign = bx.cx().const_usize(content_layout.align.abi.bytes()); @@ -554,7 +554,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // aggregate rvalues are allowed to be operands. let ty = rvalue.ty(self.mir, self.cx.tcx()); let operand = - OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(&ty))); + OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty))); (bx, operand) } } @@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { let ty = rvalue.ty(self.mir, self.cx.tcx()); - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); self.cx.spanned_layout_of(ty, span).is_zst() } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 000ddf42604..fd18f42f2dd 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -4,6 +4,11 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; +// When adding features to the below lists +// check whether they're named already elsewhere in rust +// e.g. in stdarch and whether the given name matches LLVM's +// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted + const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("aclass", Some(sym::arm_target_feature)), ("mclass", Some(sym::arm_target_feature)), @@ -50,15 +55,23 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("aes", None), ("avx", None), ("avx2", None), + ("avx512bf16", Some(sym::avx512_target_feature)), + ("avx512bitalg", Some(sym::avx512_target_feature)), ("avx512bw", Some(sym::avx512_target_feature)), ("avx512cd", Some(sym::avx512_target_feature)), ("avx512dq", Some(sym::avx512_target_feature)), ("avx512er", Some(sym::avx512_target_feature)), ("avx512f", Some(sym::avx512_target_feature)), + ("avx512gfni", Some(sym::avx512_target_feature)), ("avx512ifma", Some(sym::avx512_target_feature)), ("avx512pf", Some(sym::avx512_target_feature)), + ("avx512vaes", Some(sym::avx512_target_feature)), ("avx512vbmi", Some(sym::avx512_target_feature)), + ("avx512vbmi2", Some(sym::avx512_target_feature)), ("avx512vl", Some(sym::avx512_target_feature)), + ("avx512vnni", Some(sym::avx512_target_feature)), + ("avx512vp2intersect", Some(sym::avx512_target_feature)), + ("avx512vpclmulqdq", Some(sym::avx512_target_feature)), ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs new file mode 100644 index 00000000000..fe7a256d210 --- /dev/null +++ b/compiler/rustc_data_structures/src/functor.rs @@ -0,0 +1,82 @@ +use rustc_index::vec::{Idx, IndexVec}; +use std::mem; +use std::ptr; + +pub trait IdFunctor { + type Inner; + + fn map_id<F>(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner; +} + +impl<T> IdFunctor for Box<T> { + type Inner = T; + + #[inline] + fn map_id<F>(self, mut f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + let raw = Box::into_raw(self); + unsafe { + // SAFETY: The raw pointer points to a valid value of type `T`. + let value = ptr::read(raw); + // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the + // inverse of `Box::assume_init()` and should be safe. + let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast()); + // SAFETY: Write the mapped value back into the `Box`. + ptr::write(raw.as_mut_ptr(), f(value)); + // SAFETY: We just initialized `raw`. + raw.assume_init() + } + } +} + +impl<T> IdFunctor for Vec<T> { + type Inner = T; + + #[inline] + fn map_id<F>(mut self, mut f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + // FIXME: We don't really care about panics here and leak + // far more than we should, but that should be fine for now. + let len = self.len(); + unsafe { + self.set_len(0); + let start = self.as_mut_ptr(); + for i in 0..len { + let p = start.add(i); + ptr::write(p, f(ptr::read(p))); + } + self.set_len(len); + } + self + } +} + +impl<T> IdFunctor for Box<[T]> { + type Inner = T; + + #[inline] + fn map_id<F>(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + Vec::from(self).map_id(f).into() + } +} + +impl<I: Idx, T> IdFunctor for IndexVec<I, T> { + type Inner = T; + + #[inline] + fn map_id<F>(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + IndexVec::from_raw(self.raw.map_id(f)) + } +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 7669b78834c..6b952f20dd1 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -27,6 +27,7 @@ #![feature(extend_one)] #![feature(const_panic)] #![feature(min_const_generics)] +#![feature(new_uninit)] #![feature(once_cell)] #![feature(maybe_uninit_uninit_array)] #![allow(rustc::default_hash_types)] @@ -47,9 +48,9 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R { #[macro_export] macro_rules! likely { ($e:expr) => { - #[allow(unused_unsafe)] - { - unsafe { std::intrinsics::likely($e) } + match $e { + #[allow(unused_unsafe)] + e => unsafe { std::intrinsics::likely(e) }, } }; } @@ -57,9 +58,9 @@ macro_rules! likely { #[macro_export] macro_rules! unlikely { ($e:expr) => { - #[allow(unused_unsafe)] - { - unsafe { std::intrinsics::unlikely($e) } + match $e { + #[allow(unused_unsafe)] + e => unsafe { std::intrinsics::unlikely(e) }, } }; } @@ -70,6 +71,7 @@ pub mod box_region; pub mod captures; pub mod const_cstr; pub mod flock; +pub mod functor; pub mod fx; pub mod graph; pub mod jobserver; @@ -102,6 +104,7 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod sso; +pub mod steal; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index e598d7a683d..5d13b7f27c7 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -272,6 +272,28 @@ impl SelfProfilerRef { }) } + #[inline(always)] + pub fn generic_activity_with_args( + &self, + event_label: &'static str, + event_args: &[String], + ) -> TimingGuard<'_> { + self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { + let builder = EventIdBuilder::new(&profiler.profiler); + let event_label = profiler.get_or_alloc_cached_string(event_label); + let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { + let event_args: Vec<_> = event_args + .iter() + .map(|s| profiler.get_or_alloc_cached_string(&s[..])) + .collect(); + builder.from_label_and_args(event_label, &event_args) + } else { + builder.from_label(event_label) + }; + TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) + }) + } + /// Start profiling a query provider. Profiling continues until the /// TimingGuard returned from this call is dropped. #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 224e76845d7..e532a84cea3 100644 --- a/compiler/rustc_middle/src/ty/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -1,4 +1,5 @@ -use rustc_data_structures::sync::{MappedReadGuard, ReadGuard, RwLock}; +use crate::stable_hasher::{HashStable, StableHasher}; +use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; /// The `Steal` struct is intended to used as the value for a query. /// Specifically, we sometimes have queries (*cough* MIR *cough*) @@ -31,7 +32,7 @@ impl<T> Steal<T> { pub fn borrow(&self) -> MappedReadGuard<'_, T> { ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => bug!("attempted to read from stolen value"), + None => panic!("attempted to read from stolen value"), Some(ref v) => v, }) } @@ -42,3 +43,9 @@ impl<T> Steal<T> { value.expect("attempt to read from stolen value") } } + +impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.borrow().hash_stable(hcx, hasher); + } +} diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index a192c2eb94e..c5447612555 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -20,7 +20,7 @@ use rustc_data_structures::profiling::print_time_passes_entry; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorReported, PResult}; -use rustc_feature::{find_gated_cfg, UnstableFeatures}; +use rustc_feature::find_gated_cfg; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend}; use rustc_interface::{interface, Queries}; @@ -746,9 +746,6 @@ impl RustcDefaultCalls { } } Cfg => { - let allow_unstable_cfg = - UnstableFeatures::from_environment().is_nightly_build(); - let mut cfgs = sess .parse_sess .config @@ -763,7 +760,7 @@ impl RustcDefaultCalls { // it, this is intended to get into Cargo and then go // through to build scripts. if (name != sym::target_feature || value != Some(sym::crt_dash_static)) - && !allow_unstable_cfg + && !sess.is_nightly_build() && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() { return None; @@ -814,14 +811,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) { } } -fn usage(verbose: bool, include_unstable_options: bool) { +fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() }; let mut options = getopts::Options::new(); for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { (option.apply)(&mut options); } let message = "Usage: rustc [OPTIONS] INPUT"; - let nightly_help = if nightly_options::is_nightly_build() { + let nightly_help = if nightly_build { "\n -Z help Print unstable compiler options" } else { "" @@ -831,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - let at_path = if verbose && nightly_options::is_nightly_build() { + let at_path = if verbose && nightly_build { " @path Read newline separated options from `path`\n" } else { "" @@ -1034,7 +1031,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not // include that extra information. - usage(false, false); + let nightly_build = + rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build(); + usage(false, false, nightly_build); return None; } @@ -1063,7 +1062,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. - usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); + let unstable_enabled = nightly_options::is_unstable_enabled(&matches); + let nightly_build = nightly_options::match_is_nightly_build(&matches); + usage(matches.opt_present("verbose"), unstable_enabled, nightly_build); return None; } diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index f74e1fe61e7..305fa838afa 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -404,7 +404,6 @@ pub fn print_after_parsing( annotation.pp_ann(), false, parse.edition, - parse.injected_crate_name.get().is_some(), ) }) } else { @@ -446,7 +445,6 @@ pub fn print_after_hir_lowering<'tcx>( annotation.pp_ann(), true, parse.edition, - parse.injected_crate_name.get().is_some(), ) }) } diff --git a/compiler/rustc_error_codes/src/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md index 14cff3613e0..45804ab266e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0744.md +++ b/compiler/rustc_error_codes/src/error_codes/E0744.md @@ -1,4 +1,4 @@ -A control-flow expression was used inside a const context. +An unsupported expression was used inside a const context. Erroneous code example: @@ -12,12 +12,15 @@ const _: i32 = { }; ``` -At the moment, `if` and `match`, as well as the looping constructs `for`, -`while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`. +At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden +inside a `const`, `static`, or `const fn`. -This will be allowed at some point in the future, but the implementation is not -yet complete. See the tracking issue for [conditionals] or [loops] in a const -context for the current status. +This may be allowed at some point in the future, but the implementation is not +yet complete. See the tracking issues for [`async`] and [`?`] in `const fn`, and +(to support `for` loops in `const fn`) the tracking issues for [`impl const +Trait for Ty`] and [`&mut T`] in `const fn`. -[conditionals]: https://github.com/rust-lang/rust/issues/49146 -[loops]: https://github.com/rust-lang/rust/issues/52000 +[`async`]: https://github.com/rust-lang/rust/issues/69431 +[`?`]: https://github.com/rust-lang/rust/issues/74935 +[`impl const Trait for Ty`]: https://github.com/rust-lang/rust/issues/67792 +[`&mut T`]: https://github.com/rust-lang/rust/issues/57349 diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 56acdf699ef..c9259a1502c 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -184,16 +184,18 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } - /// Adds a span/label to be included in the resulting snippet. + /// Appends a labeled span to the diagnostic. /// - /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic - /// was first built. That means it will be shown together with the original - /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods. + /// Labels are used to convey additional context for the diagnostic's primary span. They will + /// be shown together with the original diagnostic's span, *not* with spans added by + /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because + /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed + /// either. /// - /// This span is *not* considered a ["primary span"][`MultiSpan`]; only - /// the `Span` supplied when creating the diagnostic is primary. - /// - /// [`MultiSpan`]: ../rustc_span/struct.MultiSpan.html + /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when + /// the diagnostic was constructed. However, the label span is *not* considered a + /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is + /// primary. pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self { self.0.diagnostic.span_label(span, label); self diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 302713a21db..32104e6f00d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -200,6 +200,11 @@ pub trait Emitter { true } + /// Checks if we can use colors in the current output stream. + fn supports_color(&self) -> bool { + false + } + fn source_map(&self) -> Option<&Lrc<SourceMap>>; /// Formats the substitutions of the primary_span @@ -504,6 +509,10 @@ impl Emitter for EmitterWriter { fn should_show_explain(&self) -> bool { !self.short_message } + + fn supports_color(&self) -> bool { + self.dst.supports_color() + } } /// An emitter that does nothing when emitting a diagnostic. @@ -2057,6 +2066,14 @@ impl Destination { Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), } } + + fn supports_color(&self) -> bool { + match *self { + Self::Terminal(ref stream) => stream.supports_color(), + Self::Buffered(ref buffer) => buffer.buffer().supports_color(), + Self::Raw(_, supports_color) => supports_color, + } + } } impl<'a> WritableDst<'a> { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 0df67b63eba..a0355079247 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -616,6 +616,9 @@ declare_features! ( /// Enables `#[cfg(panic = "...")]` config key. (active, cfg_panic, "1.49.0", Some(77443), None), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (active, capture_disjoint_fields, "1.49.0", Some(53488), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -639,6 +642,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::inline_const, sym::repr128, sym::unsized_locals, + sym::capture_disjoint_fields, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5c5cf609ac3..fa8edba629e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -547,6 +547,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 68ac2841fed..f965f7fdefe 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -59,7 +59,7 @@ pub enum Stability { Deprecated(&'static str, Option<&'static str>), } -#[derive(Clone, Copy, Hash)] +#[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { /// Hard errors for unstable features are active, as on beta/stable channels. Disallow, @@ -73,11 +73,20 @@ pub enum UnstableFeatures { } impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { + /// This takes into account `RUSTC_BOOTSTRAP`. + /// + /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features. + /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work. + pub fn from_environment(krate: Option<&str>) -> Self { // `true` if this is a feature-staged build, i.e., on the beta or stable channel. let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Returns whether `krate` should be counted as unstable + let is_unstable_crate = |var: &str| { + krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name)) + }; // `true` if we should enable unstable features for bootstrapping. - let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok(); + let bootstrap = std::env::var("RUSTC_BOOTSTRAP") + .map_or(false, |var| var == "1" || is_unstable_crate(&var)); match (disable_unstable_features, bootstrap) { (_, true) => UnstableFeatures::Cheat, (true, _) => UnstableFeatures::Disallow, @@ -140,3 +149,30 @@ pub use builtin_attrs::{ AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; + +#[cfg(test)] +mod test { + use super::UnstableFeatures; + + #[test] + fn rustc_bootstrap_parsing() { + let is_bootstrap = |env, krate| { + std::env::set_var("RUSTC_BOOTSTRAP", env); + matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat) + }; + assert!(is_bootstrap("1", None)); + assert!(is_bootstrap("1", Some("x"))); + // RUSTC_BOOTSTRAP allows specifying a specific crate + assert!(is_bootstrap("x", Some("x"))); + // RUSTC_BOOTSTRAP allows multiple comma-delimited crates + assert!(is_bootstrap("x,y,z", Some("x"))); + assert!(is_bootstrap("x,y,z", Some("y"))); + // Crate that aren't specified do not get unstable features + assert!(!is_bootstrap("x", Some("a"))); + assert!(!is_bootstrap("x,y,z", Some("a"))); + assert!(!is_bootstrap("x,y,z", None)); + + // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP + assert!(!is_bootstrap("0", None)); + } +} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3c28b48795f..4497c8c0eaa 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -282,6 +282,14 @@ impl GenericArg<'_> { GenericArg::Const(_) => "constant", } } + + pub fn short_descr(&self) -> &'static str { + match self { + GenericArg::Lifetime(_) => "lifetime", + GenericArg::Type(_) => "type", + GenericArg::Const(_) => "const", + } + } } #[derive(Debug, HashStable_Generic)] diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 048a81b81ba..e185ee24d17 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -15,7 +15,6 @@ use std::io::{self, Read}; use std::path::Path; use rustc_serialize::opaque::Encoder; -use rustc_session::config::nightly_options; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; @@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0; /// the Git commit hash. const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); -pub fn write_file_header(stream: &mut Encoder) { +pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) { stream.emit_raw_bytes(FILE_MAGIC); stream .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); - let rustc_version = rustc_version(); + let rustc_version = rustc_version(nightly_build); assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); stream.emit_raw_bytes(&[rustc_version.len() as u8]); stream.emit_raw_bytes(rustc_version.as_bytes()); @@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) { pub fn read_file( report_incremental_info: bool, path: &Path, + nightly_build: bool, ) -> io::Result<Option<(Vec<u8>, usize)>> { if !path.exists() { return Ok(None); @@ -93,7 +93,7 @@ pub fn read_file( let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; - if buffer != rustc_version().as_bytes() { + if buffer != rustc_version(nightly_build).as_bytes() { report_format_mismatch(report_incremental_info, path, "Different compiler version"); return Ok(None); } @@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & } } -fn rustc_version() -> String { - if nightly_options::is_nightly_build() { +fn rustc_version(nightly_build: bool) -> String { + if nightly_build { if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { return val.to_string_lossy().into_owned(); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 966faa9639d..578c045a2b4 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -53,8 +53,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> { } } -fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> { - match file_format::read_file(report_incremental_info, path) { +fn load_data( + report_incremental_info: bool, + path: &Path, + nightly_build: bool, +) -> LoadResult<(Vec<u8>, usize)> { + match file_format::read_file(report_incremental_info, path, nightly_build) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { // The file either didn't exist or was produced by an incompatible @@ -111,13 +115,14 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let expected_hash = sess.opts.dep_tracking_hash(); let mut prev_work_products = FxHashMap::default(); + let nightly_build = sess.is_nightly_build(); // If we are only building with -Zquery-dep-graph but without an actual // incr. comp. session directory, we skip this. Otherwise we'd fail // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(report_incremental_info, &work_products_path); + let load_result = load_data(report_incremental_info, &work_products_path, nightly_build); if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { // Decode the list of work_products @@ -163,7 +168,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { MaybeAsync::Async(std::thread::spawn(move || { let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(report_incremental_info, &path) { + match load_data(report_incremental_info, &path, nightly_build) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::Error { message } => LoadResult::Error { message }, LoadResult::Ok { data: (bytes, start_pos) } => { @@ -201,7 +206,11 @@ pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> { let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); - match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) { + match load_data( + sess.opts.debugging_opts.incremental_info, + &query_cache_path(sess), + sess.is_nightly_build(), + ) { LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos), _ => OnDiskCache::new_empty(sess.source_map()), } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 45cef479a4f..102a77e8e79 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -119,7 +119,7 @@ where // generate the data in a memory buffer let mut encoder = Encoder::new(Vec::new()); - file_format::write_file_header(&mut encoder); + file_format::write_file_header(&mut encoder, sess.is_nightly_build()); encode(&mut encoder); // write the data out diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index f554b51800a..6781fbc95c0 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -38,7 +38,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query pub fn canonicalize_query<V>( &self, - value: &V, + value: V, query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'tcx, V> where @@ -80,7 +80,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// out the [chapter in the rustc dev guide][c]. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response<V>(&self, value: &V) -> Canonicalized<'tcx, V> + pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -94,7 +94,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) } - pub fn canonicalize_user_type_annotation<V>(&self, value: &V) -> Canonicalized<'tcx, V> + pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -123,7 +123,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // and just use `canonicalize_query`. pub fn canonicalize_hr_query_hack<V>( &self, - value: &V, + value: V, query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'tcx, V> where @@ -293,7 +293,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { self.tcx } - fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> where T: TypeFoldable<'tcx>, { @@ -479,7 +479,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// The main `canonicalize` method, shared impl of /// `canonicalize_query` and `canonicalize_response`. fn canonicalize<V>( - value: &V, + value: V, infcx: Option<&InferCtxt<'_, 'tcx>>, tcx: TyCtxt<'tcx>, canonicalize_region_mode: &dyn CanonicalizeRegionMode, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 93e19521893..c8d66cbb695 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -59,7 +59,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; - let canonical_result = self.canonicalize_response(&query_response); + let canonical_result = self.canonicalize_response(query_response); debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); @@ -83,7 +83,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { where T: Debug + TypeFoldable<'tcx>, { - self.canonicalize_response(&QueryResponse { + self.canonicalize_response(QueryResponse { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, // Ambiguities are OK! @@ -176,7 +176,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { )); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -238,7 +238,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { - &v.var_values[BoundVar::new(index)] + v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { ( @@ -296,7 +296,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.outlives.extend( - query_response.value.region_constraints.outlives.iter().filter_map(|r_c| { + query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| { let r_c = substitute_value(self.tcx, &result_subst, r_c); // Screen out `'a: 'a` cases -- we skip the binder here but @@ -314,11 +314,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { .region_constraints .member_constraints .iter() - .map(|p_c| substitute_value(self.tcx, &result_subst, p_c)), + .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())), ); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -502,7 +502,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // `query_response.var_values` after applying the substitution // `result_subst`. let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { - query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) + query_response.substitute_projected(self.tcx, &result_subst, |v| v.var_values[index]) }; // Unify the original value for each variable with the value @@ -524,7 +524,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], result_subst: &'a CanonicalVarValues<'tcx>, ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> { - unsubstituted_region_constraints.iter().map(move |constraint| { + unsubstituted_region_constraints.iter().map(move |&constraint| { let ty::OutlivesPredicate(k1, r2) = substitute_value(self.tcx, result_subst, constraint).skip_binder(); diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 65791f6fc65..cd4f1fa3bc3 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -28,7 +28,7 @@ pub(super) trait CanonicalExt<'tcx, V> { &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, + projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable<'tcx>; @@ -39,14 +39,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { where V: TypeFoldable<'tcx>, { - self.substitute_projected(tcx, var_values, |value| value) + self.substitute_projected(tcx, var_values, |value| value.clone()) } fn substitute_projected<T>( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, + projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable<'tcx>, @@ -60,16 +60,16 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { /// Substitute the values from `var_values` into `value`. `var_values` /// must be values for the set of canonical variables that appear in /// `value`. -pub(super) fn substitute_value<'a, 'tcx, T>( +pub(super) fn substitute_value<'tcx, T>( tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - value: &'a T, + value: T, ) -> T where T: TypeFoldable<'tcx>, { if var_values.var_values.is_empty() { - value.clone() + value } else { let fld_r = |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 524efd04cfc..183fb314a00 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -389,7 +389,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { member_region, span, } => { - let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); + let hidden_ty = self.resolve_vars_if_possible(hidden_ty); unexpected_hidden_region_diagnostic( self.tcx, span, @@ -590,7 +590,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { - let ty = self.resolve_vars_if_possible(&root_ty); + let ty = self.resolve_vars_if_possible(root_ty); if ty.is_suggestable() { // don't show type `_` err.span_label(span, format!("this expression has type `{}`", ty)); @@ -661,7 +661,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => { // `last_ty` can be `!`, `expected` will have better info when present. - let t = self.resolve_vars_if_possible(&match exp_found { + let t = self.resolve_vars_if_possible(match exp_found { Some(ty::error::ExpectedFound { expected, .. }) => expected, _ => last_ty, }); @@ -1498,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: @@ -1547,7 +1547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), _ => (false, Mismatch::Fixed("type")), }; - let vals = match self.values_str(&values) { + let vals = match self.values_str(values) { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. @@ -1893,32 +1893,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn values_str( &self, - values: &ValuePairs<'tcx>, + values: ValuePairs<'tcx>, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { - match *values { - infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), - infer::Regions(ref exp_found) => self.expected_found_str(exp_found), - infer::Consts(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => { + match values { + infer::Types(exp_found) => self.expected_found_str_ty(exp_found), + infer::Regions(exp_found) => self.expected_found_str(exp_found), + infer::Consts(exp_found) => self.expected_found_str(exp_found), + infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(&pretty_exp_found) + self.expected_found_str(pretty_exp_found) } - infer::PolyTraitRefs(ref exp_found) => { + infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(&pretty_exp_found) + self.expected_found_str(pretty_exp_found) } } } fn expected_found_str_ty( &self, - exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, + exp_found: ty::error::ExpectedFound<Ty<'tcx>>, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -1931,7 +1931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( &self, - exp_found: &ty::error::ExpectedFound<T>, + exp_found: ty::error::ExpectedFound<T>, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -2180,7 +2180,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...", ); if let Some(infer::RelateParamBound(_, t)) = origin { - let t = self.resolve_vars_if_possible(&t); + let t = self.resolve_vars_if_possible(t); match t.kind() { // We've got: // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -2237,7 +2237,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values); if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = - (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values)) + (self.values_str(sup_trace.values), self.values_str(sub_trace.values)) { if sub_expected == sup_expected && sub_found == sup_found { note_and_explain_region( diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 868989539d4..fd8f46a6926 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id)); match ty_opt { Some(ty) => { - let ty = self.infcx.resolve_vars_if_possible(&ty); + let ty = self.infcx.resolve_vars_if_possible(ty); if ty.walk().any(|inner| { inner == self.target || match (inner.unpack(), self.target.unpack()) { @@ -343,7 +343,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let arg = self.resolve_vars_if_possible(&arg); + let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); let kind_str = match arg.unpack() { GenericArgKind::Type(_) => "type", @@ -686,7 +686,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Span, ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); let mut err = struct_span_err!( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 2187064ec5e..e8e0326d978 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -234,14 +234,13 @@ impl NiceRegionError<'me, 'tcx> { false }; - let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { + let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: expected_substs, }); - let actual_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { - def_id: trait_def_id, - substs: actual_substs, - }); + let actual_trait_ref = self + .infcx + .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs }); // Search the expected and actual trait references to see (a) // whether the sub/sup placeholders appear in them (sometimes diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index df3dbfca01d..5264854d8eb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -414,7 +414,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { tcx, ctxt.param_env, ctxt.assoc_item.def_id, - self.infcx.resolve_vars_if_possible(&ctxt.substs), + self.infcx.resolve_vars_if_possible(ctxt.substs), ) { Ok(Some(instance)) => instance, _ => return false, @@ -474,7 +474,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct TraitObjectVisitor(Vec<DefId>); impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index c061f485c1c..4d3217a9c0b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let Some((expected, found)) = - self.infcx.expected_found_str_ty(&ExpectedFound { expected, found }) + self.infcx.expected_found_str_ty(ExpectedFound { expected, found }) { // Highlighted the differences when showing the "expected/found" note. err.note_expected_found(&"", expected, &"", found); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index ca93b2777ab..8d0100440a8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -55,12 +55,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); let poly_fn_sig = self.tcx().fn_sig(id); - let fn_sig = self.tcx().liberate_late_bound_regions(id, &poly_fn_sig); + let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig); body.params.iter().enumerate().find_map(|(index, param)| { // May return None; sometimes the tables are not yet populated. let ty = fn_sig.inputs()[index]; let mut found_anon_region = false; - let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| { if *r == *anon_region { found_anon_region = true; replace_region diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 9ac27030ade..7fb94332cad 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -24,7 +24,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; match *origin { infer::Subtype(ref trace) => { - if let Some((expected, found)) = self.values_str(&trace.values) { + if let Some((expected, found)) = self.values_str(trace.values) { label_or_note( trace.cause.span, &format!("...so that the {}", trace.cause.as_requirement_str()), diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index d7bc636db8f..c292b2bdb30 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (mut fudger, value) = self.probe(|_| { match f() { Ok(value) => { - let value = self.resolve_vars_if_possible(&value); + let value = self.resolve_vars_if_possible(value); // At this point, `value` could in principle refer // to inference variables that have been created during diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 4a5fd4b2aa5..9d9ecf5b384 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -33,14 +33,14 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { self.infcx.commit_if_ok(|_| { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. - let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b); + let b_prime = self.infcx.replace_bound_vars_with_placeholders(b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- // but no other pre-existing region variables -- can name // the placeholders. let (a_prime, _) = - self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, &a); + self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a); debug!("a_prime={:?}", a_prime); debug!("b_prime={:?}", b_prime); @@ -66,7 +66,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - pub fn replace_bound_vars_with_placeholders<T>(&self, binder: &ty::Binder<T>) -> T + pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<T>) -> T where T: TypeFoldable<'tcx>, { @@ -113,10 +113,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!( "replace_bound_vars_with_placeholders(\ next_universe={:?}, \ - binder={:?}, \ result={:?}, \ map={:?})", - next_universe, binder, result, map, + next_universe, result, map, ); result diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index fcf1949933b..d7b2ce7ee20 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -1001,7 +1001,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&value, &mut false, |r, _db| match r { + tcx.fold_regions(value, &mut false, |r, _db| match r { ty::ReVar(rid) => self.resolve_var(*rid), _ => r, }) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index acded5351f8..6affe0e5463 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,3 @@ -//! See the Book for more information. - pub use self::freshen::TypeFreshener; pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; @@ -345,7 +343,7 @@ pub struct InferCtxt<'a, 'tcx> { } /// See the `error_reporting` module for more details. -#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] pub enum ValuePairs<'tcx> { Types(ExpectedFound<Ty<'tcx>>), Regions(ExpectedFound<ty::Region<'tcx>>), @@ -955,7 +953,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(self.commit_if_ok(|_snapshot| { let ty::SubtypePredicate { a_is_expected, a, b } = - self.replace_bound_vars_with_placeholders(&predicate); + self.replace_bound_vars_with_placeholders(predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -970,7 +968,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> UnitResult<'tcx> { self.commit_if_ok(|_snapshot| { let ty::OutlivesPredicate(r_a, r_b) = - self.replace_bound_vars_with_placeholders(&predicate); + self.replace_bound_vars_with_placeholders(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); @@ -1266,7 +1264,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { - self.resolve_vars_if_possible(&t).to_string() + self.resolve_vars_if_possible(t).to_string() } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -1274,7 +1272,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { format!("({})", tstrs.join(", ")) } - pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { + pub fn trait_ref_to_string(&self, t: ty::TraitRef<'tcx>) -> String { self.resolve_vars_if_possible(t).print_only_trait_path().to_string() } @@ -1314,7 +1312,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// is left as is. This is an idempotent operation that does /// not affect inference state in any way and so you can do it /// at will. - pub fn resolve_vars_if_possible<T>(&self, value: &T) -> T + pub fn resolve_vars_if_possible<T>(&self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -1334,9 +1332,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let mut r = resolve::UnresolvedTypeFinder::new(self); - value.visit_with(&mut r); - r.first_unresolved + value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() } pub fn probe_const_var( @@ -1349,7 +1345,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> { + pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: T) -> FixupResult<'tcx, T> { /*! * Attempts to resolve all type/region/const variables in * `value`. Region inference must have been run already (e.g., @@ -1383,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, { - let actual_ty = self.resolve_vars_if_possible(&actual_ty); + let actual_ty = self.resolve_vars_if_possible(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); // Don't report an error if actual type is `Error`. @@ -1420,7 +1416,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &ty::Binder<T>, + value: ty::Binder<T>, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where T: TypeFoldable<'tcx>, @@ -1508,7 +1504,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Option<Span>, ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); - let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); + let canonical = self.canonicalize_query((param_env, substs), &mut original_values); let (param_env, substs) = canonical.value; // The return value is the evaluated value which doesn't contain any reference to inference diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 9b2ffc7a920..0b2847658f7 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -741,7 +741,10 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &ty::Binder<T>, + ) -> ControlFlow<Self::BreakTy> { self.target_index.shift_in(1); t.super_visit_with(self); self.target_index.shift_out(1); @@ -749,7 +752,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; match r { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index eb1a7806256..16d86e6243d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -167,7 +167,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { sup_type, sub_region, origin ); - let sup_type = self.resolve_vars_if_possible(&sup_type); + let sup_type = self.resolve_vars_if_possible(sup_type); if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) { let outlives = &mut TypeOutlives::new( @@ -205,7 +205,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { implicit_region_bound, param_env, ); - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); outlives.type_must_outlive(origin, ty, region); } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 2b827f4f4ed..f69212c599b 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -124,10 +124,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { projection_ty: ty::ProjectionTy<'tcx>, ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> { let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(&projection_ty); + let erased_projection_ty = self.tcx.erase_regions(projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { if let ty::Projection(..) = ty.kind() { - let erased_ty = self.tcx.erase_regions(&ty); + let erased_ty = self.tcx.erase_regions(ty); erased_ty == erased_projection_ty } else { false diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index fe4ba5aa4e8..d72be0134fb 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -111,19 +111,17 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// involve some hashing and so forth). pub struct UnresolvedTypeFinder<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - - /// Used to find the type parameter name and location for error reporting. - pub first_unresolved: Option<(Ty<'tcx>, Option<Span>)>, } impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - UnresolvedTypeFinder { infcx, first_unresolved: None } + UnresolvedTypeFinder { infcx } } } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (Ty<'tcx>, Option<Span>); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = *t.kind() { @@ -144,8 +142,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { } else { None }; - self.first_unresolved = Some((t, ty_var_span)); - ControlFlow::BREAK + ControlFlow::Break((t, ty_var_span)) } else { // Otherwise, visit its contents. t.super_visit_with(self) @@ -164,7 +161,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { /// Full type resolution replaces all type and region variables with /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. -pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: &T) -> FixupResult<'tcx, T> +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T> where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 1a1c2637a6f..c4a2ecee096 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -60,16 +60,16 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { // TypeFoldable implementations. impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { traits::Obligation { - cause: self.cause.clone(), + cause: self.cause, recursion_depth: self.recursion_depth, predicate: self.predicate.fold_with(folder), param_env: self.param_env.fold_with(folder), } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.predicate.visit_with(visitor) } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index f6ef9840788..b0b0e4372b8 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -9,7 +9,7 @@ pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { - match pred.kind() { + match *pred.kind() { ty::PredicateKind::ForAll(binder) => { let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder)); tcx.reuse_or_mk_predicate(pred, new) diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 88d2efe96d1..0935eb2bd71 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,6 @@ #![feature(bool_to_option)] #![feature(box_syntax)] -#![feature(set_stdio)] +#![feature(internal_output_capture)] #![feature(nll)] #![feature(generator_trait)] #![feature(generators)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 548b6c03daa..82cf4ab7f5c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,6 +6,7 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; @@ -20,7 +21,6 @@ use rustc_middle::dep_graph::DepGraph; use rustc_middle::middle; use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_mir as mir; use rustc_mir_build as mir_build; @@ -239,16 +239,12 @@ fn configure_and_expand_inner<'a>( krate = sess.time("crate_injection", || { let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); - let (krate, name) = rustc_builtin_macros::standard_library_imports::inject( + rustc_builtin_macros::standard_library_imports::inject( krate, &mut resolver, &sess, alt_std_name, - ); - if let Some(name) = name { - sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized"); - } - krate + ) }); util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer()); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 1de7350a3e2..a2704c3adbf 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::ErrorReported; @@ -12,7 +13,6 @@ use rustc_incremental::DepGraphFuture; use rustc_lint::LintStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_serialize::json; use rustc_session::config::{self, OutputFilenames, OutputType}; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index d9ec6d51cdf..20a7b47313e 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -25,7 +25,7 @@ use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; -use std::io::{self, Write}; +use std::io; use std::lazy::SyncOnceCell; use std::mem; use std::ops::DerefMut; @@ -106,21 +106,6 @@ fn get_stack_size() -> Option<usize> { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -struct Sink(Arc<Mutex<Vec<u8>>>); -impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result<usize> { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} -impl io::LocalOutput for Sink { - fn clone_box(&self) -> Box<dyn io::LocalOutput> { - Box::new(Self(self.0.clone())) - } -} - /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need /// for `'static` bounds. #[cfg(not(parallel_compiler))] @@ -163,9 +148,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se let main_handler = move || { rustc_span::with_session_globals(edition, || { - if let Some(stderr) = stderr { - io::set_panic(Some(box Sink(stderr.clone()))); - } + io::set_output_capture(stderr.clone()); f() }) }; @@ -203,9 +186,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se // on the new threads. let main_handler = move |thread: rayon::ThreadBuilder| { rustc_span::SESSION_GLOBALS.set(session_globals, || { - if let Some(stderr) = stderr { - io::set_panic(Some(box Sink(stderr.clone()))); - } + io::set_output_capture(stderr.clone()); thread.run() }) }; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 467a3a42590..38c71e6e925 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -880,7 +880,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match ty.kind() { + match *ty.kind() { ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => { FfiSafe } @@ -1044,7 +1044,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); if !sig.output().is_unit() { let r = self.check_type_for_ffi(cache, sig.output()); match r { @@ -1131,16 +1131,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { struct ProhibitOpaqueTypes<'a, 'tcx> { cx: &'a LateContext<'tcx>, - ty: Option<Ty<'tcx>>, }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match ty.kind() { - ty::Opaque(..) => { - self.ty = Some(ty); - ControlFlow::BREAK - } + ty::Opaque(..) => ControlFlow::Break(ty), // Consider opaque types within projections FFI-safe if they do not normalize // to more opaque types. ty::Projection(..) => { @@ -1159,9 +1157,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; - ty.visit_with(&mut visitor); - if let Some(ty) = visitor.ty { + if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); true } else { @@ -1218,7 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) { let def_id = self.cx.tcx.hir().local_def_id(id); let sig = self.cx.tcx.fn_sig(def_id); - let sig = self.cx.tcx.erase_late_bound_regions(&sig); + let sig = self.cx.tcx.erase_late_bound_regions(sig); for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false); @@ -1295,7 +1291,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind { let item_def_id = cx.tcx.hir().local_def_id(it.hir_id); let t = cx.tcx.type_of(item_def_id); - let ty = cx.tcx.erase_regions(&t); + let ty = cx.tcx.erase_regions(t); let layout = match cx.layout_of(ty) { Ok(layout) => layout, Err( diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 8fa6e6a7101..082af087bf4 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -6,6 +6,12 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: } s.add_bounds(synstructure::AddBounds::Generics); + let body_visit = s.each(|bind| { + quote! { + ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); let body_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { @@ -16,26 +22,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: }) }); - let body_visit = s.each(|bind| { - quote! { - ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; - } - }); - s.bound_impl( quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>), quote! { fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>( - &self, + self, __folder: &mut __F ) -> Self { - match *self { #body_fold } + match self { #body_fold } } fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( &self, __folder: &mut __F - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow<__F::BreakTy> { match *self { #body_visit } ::std::ops::ControlFlow::CONTINUE } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f6570cc95d2..672073b1d34 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -14,10 +14,10 @@ macro_rules! arena_types { [] layouts: rustc_target::abi::Layout, // AdtDef are interned and compared by address [] adt_def: rustc_middle::ty::AdtDef, - [] steal_mir: rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>, + [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>, [decode] mir: rustc_middle::mir::Body<$tcx>, [] steal_promoted: - rustc_middle::ty::steal::Steal< + rustc_data_structures::steal::Steal< rustc_index::vec::IndexVec< rustc_middle::mir::Promoted, rustc_middle::mir::Body<$tcx> diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d86e8987195..37ec3d3d1ca 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -806,25 +806,34 @@ impl<'hir> Map<'hir> { /// Given a node ID, gets a list of attributes associated with the AST /// corresponding to the node-ID. pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { - let attrs = match self.find_entry(id).map(|entry| entry.node) { - Some(Node::Param(a)) => Some(&a.attrs[..]), - Some(Node::Local(l)) => Some(&l.attrs[..]), - Some(Node::Item(i)) => Some(&i.attrs[..]), - Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), - Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]), - Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]), - Some(Node::Variant(ref v)) => Some(&v.attrs[..]), - Some(Node::Field(ref f)) => Some(&f.attrs[..]), - Some(Node::Expr(ref e)) => Some(&*e.attrs), - Some(Node::Stmt(ref s)) => Some(s.kind.attrs(|id| self.item(id.id))), - Some(Node::Arm(ref a)) => Some(&*a.attrs), - Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), + let attrs = self.find_entry(id).map(|entry| match entry.node { + Node::Param(a) => &a.attrs[..], + Node::Local(l) => &l.attrs[..], + Node::Item(i) => &i.attrs[..], + Node::ForeignItem(fi) => &fi.attrs[..], + Node::TraitItem(ref ti) => &ti.attrs[..], + Node::ImplItem(ref ii) => &ii.attrs[..], + Node::Variant(ref v) => &v.attrs[..], + Node::Field(ref f) => &f.attrs[..], + Node::Expr(ref e) => &*e.attrs, + Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id.id)), + Node::Arm(ref a) => &*a.attrs, + Node::GenericParam(param) => ¶m.attrs[..], // Unit/tuple structs/variants take the attributes straight from // the struct/variant definition. - Some(Node::Ctor(..)) => return self.attrs(self.get_parent_item(id)), - Some(Node::Crate(item)) => Some(&item.attrs[..]), - _ => None, - }; + Node::Ctor(..) => self.attrs(self.get_parent_item(id)), + Node::Crate(item) => &item.attrs[..], + Node::MacroDef(def) => def.attrs, + Node::AnonConst(..) + | Node::PathSegment(..) + | Node::Ty(..) + | Node::Pat(..) + | Node::Binding(..) + | Node::TraitRef(..) + | Node::Block(..) + | Node::Lifetime(..) + | Node::Visibility(..) => &[], + }); attrs.unwrap_or(&[]) } diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 8f15c99f951..69bb4e23c4c 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -184,15 +184,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid { } } -impl<'a, T> HashStable<StableHashingContext<'a>> for ty::steal::Steal<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.borrow().hash_stable(hcx, hasher); - } -} - impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 947b016a1fc..6e5f95c4527 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -286,7 +286,7 @@ impl<'tcx, V> Canonical<'tcx, V> { pub type QueryOutlivesConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { for <'tcx> { crate::infer::canonical::Certainty, crate::infer::canonical::CanonicalVarInfo<'tcx>, @@ -294,7 +294,7 @@ CloneTypeFoldableAndLiftImpls! { } } -CloneTypeFoldableImpls! { +TrivialTypeFoldableImpls! { for <'tcx> { crate::infer::canonical::CanonicalVarInfos<'tcx>, } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 4a1d5459d1e..cdc5940d9ba 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] +#![feature(associated_type_defaults)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 921086366be..c0f2a76c19d 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -48,21 +48,21 @@ macro_rules! CloneLiftImpls { /// Used for types that are `Copy` and which **do not care arena /// allocated data** (i.e., don't need to be folded). #[macro_export] -macro_rules! CloneTypeFoldableImpls { +macro_rules! TrivialTypeFoldableImpls { (for <$tcx:lifetime> { $($ty:ty,)+ }) => { $( impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty { fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>( - &self, + self, _: &mut F ) -> $ty { - Clone::clone(self) + self } fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>( &self, _: &mut F) - -> ::std::ops::ControlFlow<()> + -> ::std::ops::ControlFlow<F::BreakTy> { ::std::ops::ControlFlow::CONTINUE } @@ -71,7 +71,7 @@ macro_rules! CloneTypeFoldableImpls { }; ($($ty:ty,)+) => { - CloneTypeFoldableImpls! { + TrivialTypeFoldableImpls! { for <'tcx> { $($ty,)+ } @@ -80,9 +80,9 @@ macro_rules! CloneTypeFoldableImpls { } #[macro_export] -macro_rules! CloneTypeFoldableAndLiftImpls { +macro_rules! TrivialTypeFoldableAndLiftImpls { ($($t:tt)*) => { - CloneTypeFoldableImpls! { $($t)* } + TrivialTypeFoldableImpls! { $($t)* } CloneLiftImpls! { $($t)* } } } @@ -96,7 +96,7 @@ macro_rules! EnumTypeFoldableImpl { $(where $($wc)*)* { fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>( - &self, + self, folder: &mut V, ) -> Self { EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) @@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl { fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>( &self, visitor: &mut V, - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow<V::BreakTy> { EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) } } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 978f08927c6..47c140e0b18 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, TyCtxt}; -use rustc_ast::CRATE_NODE_ID; +use rustc_ast::NodeId; use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -211,13 +211,14 @@ pub fn early_report_deprecation( suggestion: Option<Symbol>, lint: &'static Lint, span: Span, + node_id: NodeId, ) { if span.in_derive_expansion() { return; } let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span); - lint_buffer.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag); + lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag); } fn late_report_deprecation( diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e35ff6b996e..397d2ffd565 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -29,7 +29,7 @@ impl From<ErrorReported> for ErrorHandled { } } -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { ErrorHandled, } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index f366681bc75..0517ec5bb1a 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -67,7 +67,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(¶m_env.and(cid)); + let inputs = self.erase_regions(param_env.and(cid)); if let Some(span) = span { self.at(span).eval_to_const_value_raw(inputs) } else { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5fe7b0f647d..9289d4708de 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -420,7 +420,9 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all /// locals that are neither arguments nor the return place). #[inline] - pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { + pub fn vars_and_temps_iter( + &self, + ) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator { let arg_count = self.arg_count; let local_count = self.local_decls.len(); (arg_count + 1..local_count).map(Local::new) @@ -742,7 +744,7 @@ pub enum ImplicitSelfKind { None, } -CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } +TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { use crate::ich::StableHashingContext; @@ -2452,32 +2454,20 @@ impl UserTypeProjection { } } -CloneTypeFoldableAndLiftImpls! { ProjectionKind, } +TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::mir::ProjectionElem::*; - - let base = self.base.fold_with(folder); - let projs: Vec<_> = self - .projs - .iter() - .map(|&elem| match elem { - Deref => Deref, - Field(f, ()) => Field(f, ()), - Index(()) => Index(()), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - }) - .collect(); - - UserTypeProjection { base, projs } + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + UserTypeProjection { + base: self.base.fold_with(folder), + projs: self.projs.fold_with(folder), + } } - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with<Vs: TypeVisitor<'tcx>>( + &self, + visitor: &mut Vs, + ) -> ControlFlow<Vs::BreakTy> { self.base.visit_with(visitor) // Note: there's nothing in `self.proj` to visit. } diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs index a8b74883355..fd6bb76dc43 100644 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -75,6 +75,6 @@ impl<CTX> HashStable<CTX> for PredecessorCache { } } -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { PredecessorCache, } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 0801188b278..da8e189ba9d 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -2,8 +2,9 @@ use super::*; use crate::ty; +use rustc_data_structures::functor::IdFunctor; -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { BlockTailInfo, MirPhase, SourceInfo, @@ -15,34 +16,33 @@ CloneTypeFoldableAndLiftImpls! { } impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { use crate::mir::TerminatorKind::*; let kind = match self.kind { Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt { + SwitchInt { discr, switch_ty, targets } => SwitchInt { discr: discr.fold_with(folder), switch_ty: switch_ty.fold_with(folder), - targets: targets.clone(), + targets, }, - Drop { ref place, target, unwind } => { + Drop { place, target, unwind } => { Drop { place: place.fold_with(folder), target, unwind } } - DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace { + DropAndReplace { place, value, target, unwind } => DropAndReplace { place: place.fold_with(folder), value: value.fold_with(folder), target, unwind, }, - Yield { ref value, resume, ref resume_arg, drop } => Yield { + Yield { value, resume, resume_arg, drop } => Yield { value: value.fold_with(folder), resume, resume_arg: resume_arg.fold_with(folder), drop, }, - Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => { - let dest = - destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); + Call { func, args, destination, cleanup, from_hir_call, fn_span } => { + let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest)); Call { func: func.fold_with(folder), @@ -53,17 +53,17 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { fn_span, } } - Assert { ref cond, expected, ref msg, target, cleanup } => { + Assert { cond, expected, msg, target, cleanup } => { use AssertKind::*; let msg = match msg { BoundsCheck { len, index } => { BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } } - Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)), + Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)), OverflowNeg(op) => OverflowNeg(op.fold_with(folder)), DivisionByZero(op) => DivisionByZero(op.fold_with(folder)), RemainderByZero(op) => RemainderByZero(op.fold_with(folder)), - ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(), + ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg, }; Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } } @@ -76,7 +76,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { FalseEdge { real_target, imaginary_target } } FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm { + InlineAsm { template, operands, options, line_spans, destination } => InlineAsm { template, operands: operands.fold_with(folder), options, @@ -87,7 +87,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Terminator { source_info: self.source_info, kind } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { use crate::mir::TerminatorKind::*; match self.kind { @@ -140,61 +140,56 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.local.visit_with(visitor)?; self.projection.visit_with(visitor) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>(); - folder.tcx().intern_place_elems(&v) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { use crate::mir::Rvalue::*; - match *self { - Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), + match self { + Use(op) => Use(op.fold_with(folder)), + Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), - Ref(region, bk, ref place) => { - Ref(region.fold_with(folder), bk, place.fold_with(folder)) - } - AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)), - Len(ref place) => Len(place.fold_with(folder)), - Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), - BinaryOp(op, ref rhs, ref lhs) => { - BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - CheckedBinaryOp(op, ref rhs, ref lhs) => { + Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)), + AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)), + Len(place) => Len(place.fold_with(folder)), + Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, rhs, lhs) => BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + CheckedBinaryOp(op, rhs, lhs) => { CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) } - UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), - Discriminant(ref place) => Discriminant(place.fold_with(folder)), + UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(place) => Discriminant(place.fold_with(folder)), NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), - Aggregate(ref kind, ref fields) => { - let kind = box match **kind { + Aggregate(kind, fields) => { + let kind = kind.map_id(|kind| match kind { AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), AggregateKind::Tuple => AggregateKind::Tuple, AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( @@ -210,13 +205,13 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Generator(id, substs, movablity) => { AggregateKind::Generator(id, substs.fold_with(folder), movablity) } - }; + }); Aggregate(kind, fields.fold_with(folder)) } } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { use crate::mir::Rvalue::*; match *self { Use(ref op) => op.visit_with(visitor), @@ -263,15 +258,15 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - match *self { - Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), - Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), - Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + match self { + Operand::Copy(place) => Operand::Copy(place.fold_with(folder)), + Operand::Move(place) => Operand::Move(place.fold_with(folder)), + Operand::Constant(c) => Operand::Constant(c.fold_with(folder)), } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match *self { Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), Operand::Constant(ref c) => c.visit_with(visitor), @@ -280,10 +275,10 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; - match *self { + match self { Deref => Deref, Field(f, ty) => Field(f, ty.fold_with(folder)), Index(v) => Index(v.fold_with(folder)), @@ -295,7 +290,10 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } } - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with<Vs: TypeVisitor<'tcx>>( + &self, + visitor: &mut Vs, + ) -> ControlFlow<Vs::BreakTy> { use crate::mir::ProjectionElem::*; match self { @@ -307,41 +305,41 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Field { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - self.clone() + fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { Constant { span: self.span, user_ty: self.user_ty.fold_with(folder), literal: self.literal.fold_with(folder), } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.literal.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index d8d639ab734..638dd8ce970 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1,70 +1,70 @@ +//! # The MIR Visitor +//! +//! ## Overview +//! +//! There are two visitors, one for immutable and one for mutable references, +//! but both are generated by the following macro. The code is written according +//! to the following conventions: +//! +//! - introduce a `visit_foo` and a `super_foo` method for every MIR type +//! - `visit_foo`, by default, calls `super_foo` +//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo` +//! +//! This allows you as a user to override `visit_foo` for types are +//! interested in, and invoke (within that method) call +//! `self.super_foo` to get the default behavior. Just as in an OO +//! language, you should never call `super` methods ordinarily except +//! in that circumstance. +//! +//! For the most part, we do not destructure things external to the +//! MIR, e.g., types, spans, etc, but simply visit them and stop. This +//! avoids duplication with other visitors like `TypeFoldable`. +//! +//! ## Updating +//! +//! The code is written in a very deliberate style intended to minimize +//! the chance of things being overlooked. You'll notice that we always +//! use pattern matching to reference fields and we ensure that all +//! matches are exhaustive. +//! +//! For example, the `super_basic_block_data` method begins like this: +//! +//! ```rust +//! fn super_basic_block_data(&mut self, +//! block: BasicBlock, +//! data: & $($mutability)? BasicBlockData<'tcx>) { +//! let BasicBlockData { +//! statements, +//! terminator, +//! is_cleanup: _ +//! } = *data; +//! +//! for statement in statements { +//! self.visit_statement(block, statement); +//! } +//! +//! ... +//! } +//! ``` +//! +//! Here we used `let BasicBlockData { <fields> } = *data` deliberately, +//! rather than writing `data.statements` in the body. This is because if one +//! adds a new field to `BasicBlockData`, one will be forced to revise this code, +//! and hence one will (hopefully) invoke the correct visit methods (if any). +//! +//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. +//! That means you never write `..` to skip over fields, nor do you write `_` +//! to skip over variants in a `match`. +//! +//! The only place that `_` is acceptable is to match a field (or +//! variant argument) that does not require visiting, as in +//! `is_cleanup` above. + use crate::mir::*; use crate::ty::subst::SubstsRef; use crate::ty::{CanonicalUserTypeAnnotation, Ty}; use rustc_span::Span; -// # The MIR Visitor -// -// ## Overview -// -// There are two visitors, one for immutable and one for mutable references, -// but both are generated by the following macro. The code is written according -// to the following conventions: -// -// - introduce a `visit_foo` and a `super_foo` method for every MIR type -// - `visit_foo`, by default, calls `super_foo` -// - `super_foo`, by default, destructures the `foo` and calls `visit_foo` -// -// This allows you as a user to override `visit_foo` for types are -// interested in, and invoke (within that method) call -// `self.super_foo` to get the default behavior. Just as in an OO -// language, you should never call `super` methods ordinarily except -// in that circumstance. -// -// For the most part, we do not destructure things external to the -// MIR, e.g., types, spans, etc, but simply visit them and stop. This -// avoids duplication with other visitors like `TypeFoldable`. -// -// ## Updating -// -// The code is written in a very deliberate style intended to minimize -// the chance of things being overlooked. You'll notice that we always -// use pattern matching to reference fields and we ensure that all -// matches are exhaustive. -// -// For example, the `super_basic_block_data` method begins like this: -// -// ```rust -// fn super_basic_block_data(&mut self, -// block: BasicBlock, -// data: & $($mutability)? BasicBlockData<'tcx>) { -// let BasicBlockData { -// statements, -// terminator, -// is_cleanup: _ -// } = *data; -// -// for statement in statements { -// self.visit_statement(block, statement); -// } -// -// ... -// } -// ``` -// -// Here we used `let BasicBlockData { <fields> } = *data` deliberately, -// rather than writing `data.statements` in the body. This is because if one -// adds a new field to `BasicBlockData`, one will be forced to revise this code, -// and hence one will (hopefully) invoke the correct visit methods (if any). -// -// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. -// That means you never write `..` to skip over fields, nor do you write `_` -// to skip over variants in a `match`. -// -// The only place that `_` is acceptable is to match a field (or -// variant argument) that does not require visiting, as in -// `is_cleanup` above. - macro_rules! make_mir_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { pub trait $visitor_trait_name<'tcx> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 72360e219ec..634d50368bd 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -367,7 +367,7 @@ rustc_queries! { TypeChecking { /// Erases regions from `ty` to yield a new type. - /// Normally you would just use `tcx.erase_regions(&value)`, + /// Normally you would just use `tcx.erase_regions(value)`, /// however, which uses this query as a kind of cache. query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index b8f6675b8e2..194e275496e 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -105,7 +105,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, /////////////////////////////////////////////////////////////////////////// // Lift implementations -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { super::IfExpressionCause, super::ImplSourceDiscriminantKindData, } diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 3237147c8ba..7ab192daf4b 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -8,7 +8,7 @@ pub enum BindingMode { BindByValue(Mutability), } -CloneTypeFoldableAndLiftImpls! { BindingMode, } +TrivialTypeFoldableAndLiftImpls! { BindingMode, } impl BindingMode { pub fn convert(ba: BindingAnnotation) -> BindingMode { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ca51f2a9411..ecf2837b3e4 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -103,9 +103,9 @@ impl<'tcx> ConstKind<'tcx> { // so that we don't try to invoke this query with // any region variables. let param_env_and_substs = tcx - .erase_regions(¶m_env) + .erase_regions(param_env) .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(&substs)); + .and(tcx.erase_regions(substs)); // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3838e1b006f..36cbd36a770 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -14,7 +14,6 @@ use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; -use crate::ty::steal::Steal; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; use crate::ty::{ @@ -33,6 +32,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{ hash_stable_hashmap, HashStable, StableHasher, StableVec, }; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::ErrorReported; @@ -415,9 +415,19 @@ pub struct TypeckResults<'tcx> { /// entire variable. pub closure_captures: ty::UpvarListMap, + /// Tracks the minimum captures required for a closure; + /// see `MinCaptureInformationMap` for more details. + pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, + /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>, + + /// We sometimes treat byte string literals (which are of type `&[u8; N]`) + /// as `&[u8]`, depending on the pattern in which they are used. + /// This hashset records all instances where we behave + /// like this to allow `const_to_pat` to reliably handle this situation. + pub treat_byte_string_as_slice: ItemLocalSet, } impl<'tcx> TypeckResults<'tcx> { @@ -442,7 +452,9 @@ impl<'tcx> TypeckResults<'tcx> { tainted_by_errors: None, concrete_opaque_types: Default::default(), closure_captures: Default::default(), + closure_min_captures: Default::default(), generator_interior_types: Default::default(), + treat_byte_string_as_slice: Default::default(), } } @@ -676,7 +688,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> { tainted_by_errors, ref concrete_opaque_types, ref closure_captures, + ref closure_min_captures, ref generator_interior_types, + ref treat_byte_string_as_slice, } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -709,7 +723,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> { tainted_by_errors.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); closure_captures.hash_stable(hcx, hasher); + closure_min_captures.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); + treat_byte_string_as_slice.hash_stable(hcx, hasher); }) } } @@ -1495,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { match ret_ty.kind() { ty::FnDef(_, _) => { let sig = ret_ty.fn_sig(self); - let output = self.erase_late_bound_regions(&sig.output()); + let output = self.erase_late_bound_regions(sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); Some((output, fn_decl.output.span())) diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 48d0fc1839e..4412ba9408c 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -15,17 +15,17 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an equivalent value with all free regions removed (note /// that late-bound regions remain, because they are important for /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions<T>(self, value: &T) -> T + pub fn erase_regions<T>(self, value: T) -> T where T: TypeFoldable<'tcx>, { // If there's nothing to erase avoid performing the query at all if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { - return value.clone(); + return value; } - + debug!("erase_regions({:?})", value); let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); - debug!("erase_regions({:?}) = {:?}", value, value1); + debug!("erase_regions = {:?}", value1); value1 } } @@ -43,7 +43,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> { if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } } - fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 70a8157c04a..1883c89a151 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -44,13 +44,13 @@ use std::ops::ControlFlow; /// /// To implement this conveniently, use the derive macro located in librustc_macros. pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self; - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self; + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { self.super_fold_with(folder) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()>; - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.super_visit_with(visitor) } @@ -73,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break() + self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -142,26 +142,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn still_further_specializable(&self) -> bool { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } - - /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. - fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> { - pub struct Visitor<F>(F); - - impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor<F> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { - self.0(ty) - } - } - - self.visit_with(&mut Visitor(visit)) - } } impl TypeFoldable<'tcx> for hir::Constness { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } @@ -174,7 +161,7 @@ impl TypeFoldable<'tcx> for hir::Constness { pub trait TypeFolder<'tcx>: Sized { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T> + fn fold_binder<T>(&mut self, t: Binder<T>) -> Binder<T> where T: TypeFoldable<'tcx>, { @@ -195,23 +182,25 @@ pub trait TypeFolder<'tcx>: Sized { } pub trait TypeVisitor<'tcx>: Sized { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { + type BreakTy = !; + + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { t.super_visit_with(self) } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { p.super_visit_with(self) } } @@ -266,7 +255,7 @@ impl<'tcx> TyCtxt<'tcx> { /// and skipped. pub fn fold_regions<T>( self, - value: &T, + value: T, skipped_regions: &mut bool, mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, ) -> T @@ -329,14 +318,19 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::Region<'tcx>) -> bool, { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<T>, + ) -> ControlFlow<Self::BreakTy> { self.outer_index.shift_in(1); let result = t.as_ref().skip_binder().visit_with(self); self.outer_index.shift_out(1); result } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { ControlFlow::CONTINUE @@ -351,7 +345,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { // We're only interested in types involving regions if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) @@ -406,7 +400,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -466,7 +460,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -549,7 +543,7 @@ impl<'tcx> TyCtxt<'tcx> { /// contain escaping bound types. pub fn replace_late_bound_regions<T, F>( self, - value: &Binder<T>, + value: Binder<T>, fld_r: F, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where @@ -561,7 +555,7 @@ impl<'tcx> TyCtxt<'tcx> { let fld_c = |bound_ct, ty| { self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) }; - self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) + self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping @@ -569,7 +563,7 @@ impl<'tcx> TyCtxt<'tcx> { /// closure replaces escaping bound consts. pub fn replace_escaping_bound_vars<T, F, G, H>( self, - value: &T, + value: T, mut fld_r: F, mut fld_t: G, mut fld_c: H, @@ -609,7 +603,7 @@ impl<'tcx> TyCtxt<'tcx> { /// types. pub fn replace_bound_vars<T, F, G, H>( self, - value: &Binder<T>, + value: Binder<T>, fld_r: F, fld_t: G, fld_c: H, @@ -620,16 +614,12 @@ impl<'tcx> TyCtxt<'tcx> { H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) + self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) } /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. - pub fn liberate_late_bound_regions<T>( - self, - all_outlive_scope: DefId, - value: &ty::Binder<T>, - ) -> T + pub fn liberate_late_bound_regions<T>(self, all_outlive_scope: DefId, value: ty::Binder<T>) -> T where T: TypeFoldable<'tcx>, { @@ -683,7 +673,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. - pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T + pub fn erase_late_bound_regions<T>(self, value: Binder<T>) -> T where T: TypeFoldable<'tcx>, { @@ -698,7 +688,7 @@ impl<'tcx> TyCtxt<'tcx> { /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. - pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T> + pub fn anonymize_late_bound_regions<T>(self, sig: Binder<T>) -> Binder<T> where T: TypeFoldable<'tcx>, { @@ -740,7 +730,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -804,7 +794,7 @@ pub fn shift_region<'tcx>( } } -pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T +pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T where T: TypeFoldable<'tcx>, { @@ -813,6 +803,9 @@ where value.fold_with(&mut Shifter::new(tcx, amount)) } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundEscapingVars; + /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a /// bound region or a bound type. /// @@ -844,93 +837,114 @@ struct HasEscapingVarsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { + type BreakTy = FoundEscapingVars; + + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { // If the outer-exclusive-binder is *strictly greater* than // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the // content in `t`). Therefore, `t` has some escaping vars. if t.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { // If the region is bound by `outer_index` or anything outside // of outer index, then it escapes the binders we have // visited. if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // we don't have a `visit_infer_const` callback, so we have to // hook in here to catch this case (annoying...), but // otherwise we do want to remember to visit the rest of the // const, as it has types/regions embedded in a lot of other // places. match ct.val { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK, + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { + ControlFlow::Break(FoundEscapingVars) + } _ => ct.super_visit_with(self), } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { if predicate.inner.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundFlags; + // FIXME: Optimize for checking for infer flags struct HasTypeFlagsVisitor { flags: ty::TypeFlags, } impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + type BreakTy = FoundFlags; + + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags(), self.flags ); - if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if t.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", predicate, predicate.inner.flags, self.flags ); if predicate.inner.flags.intersects(self.flags) { - ControlFlow::BREAK + ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE } @@ -964,14 +978,14 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { self.current_index.shift_in(1); let result = t.super_visit_with(self); self.current_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { // if we are only looking for "constrained" region, we have to // ignore the inputs to a projection, as they may not appear // in the normalized form @@ -984,7 +998,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // if we are only looking for "constrained" region, we have to // ignore the inputs of an unevaluated const, as they may not appear // in the normalized form @@ -997,7 +1011,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { c.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { self.regions.insert(br); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 306cebd9cb7..f52466d85f8 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -359,15 +359,15 @@ impl<'tcx> Instance<'tcx> { // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)` // below is more likely to ignore the bounds in scope (e.g. if the only // generic parameters mentioned by `substs` were lifetime ones). - let substs = tcx.erase_regions(&substs); + let substs = tcx.erase_regions(substs); // FIXME(eddyb) should this always use `param_env.with_reveal_all()`? if let Some((did, param_did)) = def.as_const_arg() { tcx.resolve_instance_of_const_arg( - tcx.erase_regions(¶m_env.and((did, param_did, substs))), + tcx.erase_regions(param_env.and((did, param_did, substs))), ) } else { - tcx.resolve_instance(tcx.erase_regions(¶m_env.and((def.did, substs)))) + tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, substs)))) } } @@ -452,7 +452,7 @@ impl<'tcx> Instance<'tcx> { let self_ty = tcx.mk_closure(closure_did, substs); let sig = substs.as_closure().sig(); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); @@ -485,7 +485,7 @@ impl<'tcx> Instance<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - v: &T, + v: T, ) -> T where T: TypeFoldable<'tcx> + Clone, @@ -493,7 +493,7 @@ impl<'tcx> Instance<'tcx> { if let Some(substs) = self.substs_for_mir_body() { tcx.subst_and_normalize_erasing_regions(substs, param_env, v) } else { - tcx.normalize_erasing_regions(param_env, v.clone()) + tcx.normalize_erasing_regions(param_env, v) } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 1e93c3650b8..5626c864fe1 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -176,7 +176,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty), LayoutError::SizeOverflow(ty) => { - write!(f, "the type `{}` is too big for the current architecture", ty) + write!(f, "values of the type `{}` are too big for the current architecture", ty) } } } @@ -1756,7 +1756,7 @@ impl<'tcx> SizeSkeleton<'tcx> { match tail.kind() { ty::Param(_) | ty::Projection(_) => { debug_assert!(tail.has_param_types_or_consts()); - Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) }) + Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( "SizeSkeleton::compute({}): layout errored ({}), yet \ @@ -2545,7 +2545,7 @@ where ) -> Self { debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); use rustc_target::spec::abi::Abi::*; let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index db11746971d..6a67935cd98 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -6,6 +6,7 @@ pub use self::IntVarValue::*; pub use self::Variance::*; use crate::hir::exports::ExportMap; +use crate::hir::place::Place as HirPlace; use crate::ich::StableHashingContext; use crate::middle::cstore::CrateStoreDyn; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; @@ -106,7 +107,6 @@ pub mod outlives; pub mod print; pub mod query; pub mod relate; -pub mod steal; pub mod subst; pub mod trait_def; pub mod util; @@ -686,6 +686,12 @@ pub struct UpvarId { pub closure_expr_id: LocalDefId, } +impl UpvarId { + pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId { + UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id } + } +} + #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. @@ -768,6 +774,56 @@ pub struct UpvarBorrow<'tcx> { pub region: ty::Region<'tcx>, } +/// Given the closure DefId this map provides a map of root variables to minimum +/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure. +pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>; + +/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`. +/// Used to track the minimum set of `Place`s that need to be captured to support all +/// Places captured by the closure starting at a given root variable. +/// +/// This provides a convenient and quick way of checking if a variable being used within +/// a closure is a capture of a local variable. +pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>; + +/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s. +pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>; + +/// A `Place` and the corresponding `CaptureInfo`. +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct CapturedPlace<'tcx> { + pub place: HirPlace<'tcx>, + pub info: CaptureInfo<'tcx>, +} + +/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) +/// for a particular capture as well as identifying the part of the source code +/// that triggered this capture to occur. +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +pub struct CaptureInfo<'tcx> { + /// Expr Id pointing to use that resulted in selecting the current capture kind + /// + /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is + /// possible that we don't see the use of a particular place resulting in expr_id being + /// None. In such case we fallback on uvpars_mentioned for span. + /// + /// Eg: + /// ```rust,no_run + /// let x = 5; + /// + /// let c = || { + /// let _ = x + /// }; + /// ``` + /// + /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured, + /// but we won't see it being used during capture analysis, since it's essentially a discard. + pub expr_id: Option<hir::HirId>, + + /// Capture mode that was selected + pub capture_kind: UpvarCapture<'tcx>, +} + pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>; pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>; @@ -1789,11 +1845,11 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { - fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self { ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.caller_bounds().visit_with(visitor)?; self.reveal().visit_with(visitor) } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index a594a8ad512..9d97815a5f1 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -30,7 +30,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(&value); + let value = self.erase_regions(value); if !value.has_projections() { value } else { @@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn normalize_erasing_late_bound_regions<T>( self, param_env: ty::ParamEnv<'tcx>, - value: &ty::Binder<T>, + value: ty::Binder<T>, ) -> T where T: TypeFoldable<'tcx>, @@ -65,7 +65,7 @@ impl<'tcx> TyCtxt<'tcx> { self, param_substs: SubstsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1e4fd0921ee..38f8e779f6a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1750,7 +1750,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { define_scoped_cx!(self); let mut region_index = self.region_index; - let new_value = self.tcx.replace_late_bound_regions(value, |br| { + let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { let _ = start_or_continue(&mut self, "for<", ", "); let br = match br { ty::BrNamed(_, name) => { @@ -1796,7 +1796,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { self.0.insert(name); } diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 7ba4d5a14df..187f86a52f4 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -28,13 +28,13 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{self, ImplSource}; -use crate::ty::steal::Steal; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableVec; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 89fd803fe51..94e69a93a6b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,12 +7,12 @@ use crate::mir::ProjectionKind; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; +use rustc_data_structures::functor::IdFunctor; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::CRATE_DEF_INDEX; use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; use std::fmt; use std::ops::ControlFlow; use std::rc::Rc; @@ -274,7 +274,7 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { // For things that don't carry any arena-allocated data (and are // copy...), just add them to this list. -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { (), bool, usize, @@ -725,21 +725,21 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { /// AdtDefs are basically the same as a DefId. impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.0.visit_with(visitor)?; self.1.visit_with(visitor) } @@ -748,11 +748,11 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (A, B, C) { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (A, B, C) { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) { (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.0.visit_with(visitor)?; self.1.visit_with(visitor)?; self.2.visit_with(visitor) @@ -774,106 +774,107 @@ EnumTypeFoldableImpl! { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Rc::new((**self).fold_with(folder)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + // FIXME: Reuse the `Rc` here. + Rc::new((*self).clone().fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Arc::new((**self).fold_with(folder)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + // FIXME: Reuse the `Arc` here. + Arc::new((*self).clone().fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - box content + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + self.map_id(|value| value.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + self.map_id(|t| t.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice() + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + self.map_id(|t| t.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.map_bound_ref(|ty| ty.fold_with(folder)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + self.map_bound(|ty| ty.fold_with(folder)) } - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { folder.fold_binder(self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.as_ref().skip_binder().visit_with(visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_binder(self) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_existential_predicates(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|p| p.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { use crate::ty::InstanceDef::*; Self { substs: self.substs.fold_with(folder), @@ -893,7 +894,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { use crate::ty::InstanceDef::*; self.substs.visit_with(visitor)?; match self.def { @@ -915,36 +916,36 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { Self { instance: self.instance.fold_with(folder), promoted: self.promoted } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.instance.visit_with(visitor) } } impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let kind = match self.kind() { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + let kind = match *self.kind() { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(*tid, substs.fold_with(folder)), - ty::Dynamic(ref trait_ty, ref region) => { + ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), + ty::Dynamic(trait_ty, region) => { ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) } ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(*def_id, substs.fold_with(folder)), + ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), *mutbl), + ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), ty::Generator(did, substs, movability) => { - ty::Generator(*did, substs.fold_with(folder), *movability) + ty::Generator(did, substs.fold_with(folder), movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(*did, substs.fold_with(folder)), - ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), - ty::Opaque(did, substs) => ty::Opaque(*did, substs.fold_with(folder)), + ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), + ty::Projection(data) => ty::Projection(data.fold_with(folder)), + ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), ty::Bool | ty::Char @@ -964,11 +965,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) } } - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_ty(*self) + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + folder.fold_ty(self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => { @@ -1010,40 +1011,40 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_ty(self) } } impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self { + self } - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_region(*self) + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + folder.fold_region(self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_region(*self) } } impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder); - folder.tcx().reuse_or_mk_predicate(*self, new) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + let new = ty::PredicateKind::super_fold_with(self.inner.kind, folder); + folder.tcx().reuse_or_mk_predicate(self, new) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_predicate(*self) } @@ -1057,53 +1058,53 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|p| p.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|x| x.fold_with(folder)).collect() + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + self.map_id(|x| x.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { let ty = self.ty.fold_with(folder); let val = self.val.fold_with(folder); if ty != self.ty || val != self.val { folder.tcx().mk_const(ty::Const { ty, val }) } else { - *self + self } } - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_const(*self) + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + folder.fold_const(self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.ty.visit_with(visitor)?; self.val.visit_with(visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_const(self) } } impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - match *self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { + match self { ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), ty::ConstKind::Unevaluated(did, substs, promoted) => { @@ -1112,11 +1113,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) - | ty::ConstKind::Error(_) => *self, + | ty::ConstKind::Error(_) => self, } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), @@ -1130,42 +1131,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self { + self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } } - -// Does the equivalent of -// ``` -// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); -// folder.tcx().intern_*(&v) -// ``` -fn fold_list<'tcx, F, T>( - list: &'tcx ty::List<T>, - folder: &mut F, - intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>, -) -> &'tcx ty::List<T> -where - F: TypeFolder<'tcx>, - T: TypeFoldable<'tcx> + PartialEq + Copy, -{ - let mut iter = list.iter(); - // Look for the first element that changed - if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { - let new_t = t.fold_with(folder); - if new_t == t { None } else { Some((i, new_t)) } - }) { - // An element changed, prepare to intern the resulting list - let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); - new_list.extend_from_slice(&list[..i]); - new_list.push(new_t); - new_list.extend(iter.map(|t| t.fold_with(folder))); - intern(folder.tcx(), &new_list) - } else { - list - } -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 384d08f8348..4bf16436855 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1001,7 +1001,7 @@ impl<T> Binder<T> { T: TypeFoldable<'tcx>, { if value.has_escaping_bound_vars() { - Binder::bind(super::fold::shift_vars(tcx, &value, 1)) + Binder::bind(super::fold::shift_vars(tcx, value, 1)) } else { Binder::dummy(value) } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 07f775cf8b1..5d1b976ae97 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -152,7 +152,7 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { } impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), GenericArgKind::Type(ty) => ty.fold_with(folder).into(), @@ -160,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor), @@ -363,7 +363,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { // This code is hot enough that it's worth specializing for the most // common length lists, to avoid the overhead of `SmallVec` creation. // The match arms are in order of frequency. The 1, 2, and 0 cases are @@ -392,7 +392,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -405,12 +405,12 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { // there is more information available (for better errors). pub trait Subst<'tcx>: Sized { - fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { self.subst_spanned(tcx, substs, None) } fn subst_spanned( - &self, + self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>], span: Option<Span>, @@ -419,13 +419,13 @@ pub trait Subst<'tcx>: Sized { impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { fn subst_spanned( - &self, + self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>], span: Option<Span>, ) -> T { let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 }; - (*self).fold_with(&mut folder) + self.fold_with(&mut folder) } } @@ -448,7 +448,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { self.binders_passed += 1; let t = t.super_fold_with(self); self.binders_passed -= 1; @@ -634,7 +634,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { return val; } - let result = ty::fold::shift_vars(self.tcx(), &val, self.binders_passed); + let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 5f117e19eca..e23c3f51967 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -160,7 +160,7 @@ impl<'tcx> TyCtxt<'tcx> { // We want the type_id be independent of the types free regions, so we // erase them. The erase_regions() call will also anonymize bound // regions, which is desirable too. - let ty = self.erase_regions(&ty); + let ty = self.erase_regions(ty); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -1130,6 +1130,37 @@ pub fn needs_drop_components( } } +// Does the equivalent of +// ``` +// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); +// folder.tcx().intern_*(&v) +// ``` +pub fn fold_list<'tcx, F, T>( + list: &'tcx ty::List<T>, + folder: &mut F, + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>, +) -> &'tcx ty::List<T> +where + F: TypeFolder<'tcx>, + T: TypeFoldable<'tcx> + PartialEq + Copy, +{ + let mut iter = list.iter(); + // Look for the first element that changed + if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { + let new_t = t.fold_with(folder); + if new_t == t { None } else { Some((i, new_t)) } + }) { + // An element changed, prepare to intern the resulting list + let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); + new_list.extend_from_slice(&list[..i]); + new_list.push(new_t); + new_list.extend(iter.map(|t| t.fold_with(folder))); + intern(folder.tcx(), &new_list) + } else { + list + } +} + #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub struct AlwaysRequiresDrop; diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 4256f6e39d5..41f3edaa413 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -383,16 +383,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_field_from_ty(&ty, field, variant_index) } ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // `tcx.upvars_mentioned(def_id)` returns an `Option`, which is `None` in case - // the closure comes from another crate. But in that case we wouldn't - // be borrowck'ing it, so we can just unwrap: - let (&var_id, _) = self - .infcx - .tcx - .upvars_mentioned(def_id) - .unwrap() - .get_index(field.index()) - .unwrap(); + // We won't be borrowck'ing here if the closure came from another crate, + // so it's safe to call `expect_local`. + // + // We know the field exists so it's safe to call operator[] and `unwrap` here. + let (&var_id, _) = + self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] + .get_index(field.index()) + .unwrap(); self.infcx.tcx.hir().name(var_id).to_string() } @@ -967,9 +965,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for ((upvar_hir_id, upvar), place) in - self.infcx.tcx.upvars_mentioned(def_id)?.iter().zip(places) + for (upvar_hir_id, place) in + self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] + .keys() + .zip(places) { + let span = self.infcx.tcx.upvars_mentioned(local_did)?[upvar_hir_id].span; match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -991,7 +992,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let usage_span = match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) { ty::UpvarCapture::ByValue(Some(span)) => span, - _ => upvar.span, + _ => span, }; return Some((*args_span, generator_kind, usage_span)); } diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index a5a7012852d..3586be2804d 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -876,7 +876,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(&type_test.generic_kind); + let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); // Skip duplicate-ish errors. if deduplicate_errors.insert(( @@ -1006,7 +1006,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("try_promote_type_test_subject(ty = {:?})", ty); - let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| { + let ty = tcx.fold_regions(ty, &mut false, |r, _depth| { let region_vid = self.to_region_vid(r); // The challenge if this. We have some region variable `r` @@ -1248,7 +1248,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&value, &mut false, |r, _db| { + tcx.fold_regions(value, &mut false, |r, _db| { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs index 325dca8c8ca..f7c902355cb 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs @@ -63,7 +63,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = - infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region { + infcx.tcx.fold_regions(substs, &mut false, |region, _| match *region { ty::ReVar(vid) => { subst_regions.push(vid); self.definitions[vid].external_name.unwrap_or_else(|| { @@ -94,7 +94,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { subst_regions.dedup(); let universal_concrete_type = - infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region { + infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { ty::ReVar(vid) => subst_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) @@ -139,7 +139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&ty, &mut false, |region, _| match *region { + tcx.fold_regions(ty, &mut false, |region, _| match *region { ty::ReVar(vid) => { // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs index 5df033b48c1..e563e37adc2 100644 --- a/compiler/rustc_mir/src/borrow_check/renumber.rs +++ b/compiler/rustc_mir/src/borrow_check/renumber.rs @@ -26,7 +26,7 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -43,7 +43,7 @@ struct NLLVisitor<'a, 'tcx> { } impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { - fn renumber_regions<T>(&mut self, value: &T) -> T + fn renumber_regions<T>(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -70,7 +70,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { _: Location, ) -> Option<PlaceElem<'tcx>> { if let PlaceElem::Field(field, ty) = elem { - let new_ty = self.renumber_regions(&ty); + let new_ty = self.renumber_regions(ty); if new_ty != ty { return Some(PlaceElem::Field(field, new_ty)); @@ -83,7 +83,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { debug!("visit_substs(substs={:?}, location={:?})", substs, location); - *substs = self.renumber_regions(&{ *substs }); + *substs = self.renumber_regions(*substs); debug!("visit_substs: substs={:?}", substs); } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs index 444f9fe8d0a..b7d22fab3dd 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( body.span, LateBoundRegionConversionTime::FnCall, - &poly_sig, + poly_sig, ) .0, ) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 409399094e8..a5c45452dec 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -784,7 +784,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }; if let Some(field) = variant.fields.get(field.index()) { - Ok(self.cx.normalize(&field.ty(tcx, substs), location)) + Ok(self.cx.normalize(field.ty(tcx, substs), location)) } else { Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) } @@ -1245,7 +1245,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_owner_def_id, dummy_body_id, param_env, - &anon_ty, + anon_ty, locations.span(body), )); debug!( @@ -1271,7 +1271,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); + let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { *def_id == opaque_def_id } else { @@ -1296,7 +1296,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let subst_opaque_defn_ty = opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); let renumbered_opaque_defn_ty = - renumber::renumber_regions(infcx, &subst_opaque_defn_ty); + renumber::renumber_regions(infcx, subst_opaque_defn_ty); debug!( "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", @@ -1601,7 +1601,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars( term.source_info.span, LateBoundRegionConversionTime::FnCall, - &sig, + sig, ); let sig = self.normalize(sig, term_location); self.check_call_dest(body, term, &sig, destination, term_location); @@ -1900,7 +1900,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(&ty); + let erased_ty = tcx.erase_regions(ty); if !erased_ty.is_sized(tcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 4742113b1a5..7ad38a1f82c 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -438,7 +438,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( FR, self.mir_def.did, - &bound_inputs_and_output, + bound_inputs_and_output, &mut indices, ); // Converse of above, if this is a function then the late-bound regions declared on its @@ -522,7 +522,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!("defining_ty (pre-replacement): {:?}", defining_ty); let defining_ty = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, &defining_ty); + self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); match *defining_ty.kind() { ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), @@ -543,7 +543,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs); + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); DefiningTy::Const(self.mir_def.did.to_def_id(), substs) } } @@ -628,7 +628,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id); - let sig = indices.fold_to_region_vids(tcx, &sig); + let sig = indices.fold_to_region_vids(tcx, sig); sig.inputs_and_output() } @@ -637,7 +637,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // "output" (the type of the constant). assert_eq!(self.mir_def.did.to_def_id(), def_id); let ty = tcx.type_of(self.mir_def.def_id_for_type_of()); - let ty = indices.fold_to_region_vids(tcx, &ty); + let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) } } @@ -648,7 +648,7 @@ trait InferCtxtExt<'tcx> { fn replace_free_regions_with_nll_infer_vars<T>( &self, origin: NLLRegionVariableOrigin, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>; @@ -657,7 +657,7 @@ trait InferCtxtExt<'tcx> { &self, origin: NLLRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: &ty::Binder<T>, + value: ty::Binder<T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where @@ -674,7 +674,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_free_regions_with_nll_infer_vars<T>( &self, origin: NLLRegionVariableOrigin, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, @@ -686,7 +686,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { &self, origin: NLLRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: &ty::Binder<T>, + value: ty::Binder<T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where @@ -771,7 +771,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// Replaces all free regions in `value` with region vids, as /// returned by `to_region_vid`. - pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: &T) -> T + pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs index d1d507e54ef..d16366fded9 100644 --- a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs +++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs @@ -152,7 +152,7 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>( let ty = place.ty(body, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); - let erased_ty = tcx.erase_regions(&ty); + let erased_ty = tcx.erase_regions(ty); if erased_ty.needs_drop(tcx, ctxt.param_env) { each_child(child); } else { diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 0f86a181a55..05b4d1c410d 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -505,7 +505,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, value: T, ) -> T { - frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value) + frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 77f4593fa16..fa7036f4e5b 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -21,7 +21,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); - let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref)); + let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); // All vtables must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, ty)?; @@ -37,7 +37,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let methods = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); - let trait_ref = self.tcx.erase_regions(&trait_ref); + let trait_ref = self.tcx.erase_regions(trait_ref); self.tcx.vtable_methods(trait_ref) } else { @@ -143,7 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?; trace!("Found drop fn: {:?}", drop_instance); let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index fce5553c993..e49b1c9f64d 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -18,7 +18,9 @@ where }; impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if !c.needs_subst() { return ControlFlow::CONTINUE; } @@ -29,7 +31,7 @@ where } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if !ty.needs_subst() { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 938181abff2..a6f90992172 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -546,7 +546,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - &value, + value, ) } } @@ -1118,7 +1118,7 @@ impl RootCollector<'_, 'v> { // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = self.tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); let start_instance = Instance::resolve( self.tcx, diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 037b80e4bf2..d5a845dd76f 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -304,7 +304,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &tcx.type_of(impl_def_id), + tcx.type_of(impl_def_id), ); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index c2ebc954a22..0ce1c5a0489 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -283,7 +283,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -318,7 +318,9 @@ struct HasUsedGenericParams<'a> { } impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -336,7 +338,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index b2fa4b11f36..3a1fa0018c1 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -135,7 +135,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) // Check if this is a generator, if so, return the drop glue for it if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); - return body.subst(tcx, substs); + return body.clone().subst(tcx, substs); } let substs = if let Some(ty) = ty { @@ -144,7 +144,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) InternalSubsts::identity_for_item(tcx, def_id) }; let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); @@ -338,7 +338,7 @@ impl CloneShimBuilder<'tcx> { // or access fields of a Place of type TySelf. let substs = tcx.mk_substs_trait(self_ty, &[]); let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); CloneShimBuilder { @@ -656,7 +656,7 @@ fn build_call_shim<'tcx>( // to substitute into the signature of the shim. It is not necessary for users of this // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { - let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); + let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -671,7 +671,7 @@ fn build_call_shim<'tcx>( let def_id = instance.def_id(); let sig = tcx.fn_sig(def_id); - let mut sig = tcx.erase_late_bound_regions(&sig); + let mut sig = tcx.erase_late_bound_regions(sig); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); if let Some(sig_substs) = sig_substs { diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index bd51136b8db..d2e65abfbc7 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -4,7 +4,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable { if ccx.is_const_stable_const_fn() { err.help("Const-stable functions can only call other const-stable functions"); - } else if nightly_options::is_nightly_build() { + } else if ccx.tcx.sess.is_nightly_build() { if let Some(feature) = feature { err.help(&format!( "add `#![feature({})]` to the crate attributes to enable", diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 039d4753a8c..dc413f8dd2d 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -720,13 +720,13 @@ fn sanitize_witness<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, witness: Ty<'tcx>, - upvars: &Vec<Ty<'tcx>>, + upvars: Vec<Ty<'tcx>>, saved_locals: &GeneratorSavedLocals, ) { let did = body.source.def_id(); let allowed_upvars = tcx.erase_regions(upvars); let allowed = match witness.kind() { - ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), + &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s), _ => { tcx.sess.delay_span_bug( body.span, @@ -1303,7 +1303,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - sanitize_witness(tcx, body, interior, &upvars, &liveness_info.saved_locals); + sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); if tcx.sess.opts.debugging_opts.validate_mir { let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index aae98f5b6d8..094c1513118 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -122,7 +122,7 @@ impl Inliner<'tcx> { let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - callee_body, + callee_body.clone(), ); let old_blocks = caller_body.basic_blocks().next_index(); @@ -459,6 +459,7 @@ impl Inliner<'tcx> { tcx: self.tcx, callsite_span: callsite.source_info.span, body_span: callee_body.span, + always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -490,6 +491,34 @@ impl Inliner<'tcx> { } } + // If there are any locals without storage markers, give them storage only for the + // duration of the call. + for local in callee_body.vars_and_temps_iter() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(new_local), + }); + } + } + if let Some(block) = callsite.target { + // To avoid repeated O(n) insert, push any new statements to the end and rotate + // the slice once. + let mut n = 0; + for local in callee_body.vars_and_temps_iter().rev() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(new_local), + }); + n += 1; + } + } + caller_body[block].statements.rotate_right(n); + } + // Insert all of the (mapped) parts of the callee body into the caller. caller_body.local_decls.extend( // FIXME(eddyb) make `Range<Local>` iterable so that we can use @@ -670,6 +699,7 @@ struct Integrator<'a, 'tcx> { tcx: TyCtxt<'tcx>, callsite_span: Span, body_span: Span, + always_live_locals: BitSet<Local>, } impl<'a, 'tcx> Integrator<'a, 'tcx> { @@ -759,6 +789,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) = + statement.kind + { + self.always_live_locals.remove(local); + } + self.super_statement(statement, location); + } + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { // Don't try to modify the implicit `_0` access on return (`return` terminators are // replaced down below anyways). diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 2f81db8af2f..e86d11e248f 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -1,6 +1,7 @@ use crate::{shim, util}; use required_consts::RequiredConstsVisitor; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -8,7 +9,6 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; use std::borrow::Cow; diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index 876ecee80c6..75399e9c32c 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -181,6 +181,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if self.body.local_decls.get(*local).is_none() { + self.fail( + location, + format!("local {:?} has no corresponding declaration in `body.local_decls`", local), + ); + } + if self.reachable_blocks.contains(location.block) && context.is_use() { // Uses of locals must occur while the local's storage is allocated. self.storage_liveness.seek_after_primary_effect(location); diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 8bee8417c51..cd60602b088 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -640,7 +640,7 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet<AllocId>); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index f9995f43f5a..c50389a850e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -24,7 +24,7 @@ use super::lints; crate fn mir_built<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>, -) -> &'tcx ty::steal::Steal<Body<'tcx>> { +) -> &'tcx rustc_data_structures::steal::Steal<Body<'tcx>> { if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } @@ -240,7 +240,7 @@ fn liberated_closure_env_ty( }; let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap(); - tcx.erase_late_bound_regions(&closure_env_ty) + tcx.erase_late_bound_regions(closure_env_ty) } #[derive(Debug, PartialEq, Eq)] diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 6ed7ed575fc..47c0400533b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -387,8 +387,9 @@ fn make_mirror_unadjusted<'a, 'tcx>( } }; let upvars = cx - .tcx - .upvars_mentioned(def_id) + .typeck_results() + .closure_captures + .get(&def_id) .iter() .flat_map(|upvars| upvars.iter()) .zip(substs.upvar_tys()) diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 5e7e81eba62..6bea2381862 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -364,14 +364,14 @@ impl<'tcx> Pat<'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. #[derive(Debug, Clone)] -crate struct PatStack<'p, 'tcx> { +struct PatStack<'p, 'tcx> { pats: SmallVec<[&'p Pat<'tcx>; 2]>, /// Cache for the constructor of the head head_ctor: OnceCell<Constructor<'tcx>>, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - crate fn from_pattern(pat: &'p Pat<'tcx>) -> Self { + fn from_pattern(pat: &'p Pat<'tcx>) -> Self { Self::from_vec(smallvec![pat]) } @@ -455,17 +455,17 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { /// A 2D matrix. #[derive(Clone, PartialEq)] -crate struct Matrix<'p, 'tcx> { +struct Matrix<'p, 'tcx> { patterns: Vec<PatStack<'p, 'tcx>>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { - crate fn empty() -> Self { + fn empty() -> Self { Matrix { patterns: vec![] } } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. - crate fn push(&mut self, row: PatStack<'p, 'tcx>) { + fn push(&mut self, row: PatStack<'p, 'tcx>) { if let Some(rows) = row.expand_or_pat() { for row in rows { // We recursively expand the or-patterns of the new rows. @@ -588,7 +588,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. - crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { + fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(def, ..) => { def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() @@ -1392,13 +1392,12 @@ impl<'tcx> Usefulness<'tcx> { pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, - is_top_level: bool, ) -> Self { match self { UsefulWithWitness(witnesses) => { let new_witnesses = if ctor.is_wildcard() { let missing_ctors = MissingConstructors::new(pcx); - let new_patterns = missing_ctors.report_patterns(pcx, is_top_level); + let new_patterns = missing_ctors.report_patterns(pcx); witnesses .into_iter() .flat_map(|witness| { @@ -1440,7 +1439,7 @@ impl<'tcx> Usefulness<'tcx> { } #[derive(Copy, Clone, Debug)] -crate enum WitnessPreference { +enum WitnessPreference { ConstructWitness, LeaveOutWitness, } @@ -1454,6 +1453,9 @@ struct PatCtxt<'a, 'p, 'tcx> { ty: Ty<'tcx>, /// Span of the current pattern under investigation. span: Span, + /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a + /// subpattern. + is_top_level: bool, } /// A witness of non-exhaustiveness for error reporting, represented @@ -1493,7 +1495,8 @@ struct PatCtxt<'a, 'p, 'tcx> { crate struct Witness<'tcx>(Vec<Pat<'tcx>>); impl<'tcx> Witness<'tcx> { - crate fn single_pattern(self) -> Pat<'tcx> { + /// Asserts that the witness contains a single pattern, and returns it. + fn single_pattern(self) -> Pat<'tcx> { assert_eq!(self.0.len(), 1); self.0.into_iter().next().unwrap() } @@ -1585,11 +1588,12 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that - // an empty match will still be considered exhaustive because that case is handled - // separately in `check_match`. - let is_secretly_empty = - def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns; + // as though it had an "unknown" constructor to avoid exposing its emptiness. The + // exception is if the pattern is at the top level, because we want empty matches to be + // considered exhaustive. + let is_secretly_empty = def.variants.is_empty() + && !cx.tcx.features().exhaustive_patterns + && !pcx.is_top_level; if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] @@ -1635,6 +1639,13 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc let max = size.truncate(u128::MAX); vec![make_range(0, max)] } + // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot + // expose its emptiness. The exception is if the pattern is at the top level, because we + // want empty matches to be considered exhaustive. + ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { + vec![NonExhaustive] + } + ty::Never => vec![], _ if cx.is_uninhabited(pcx.ty) => vec![], ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single], // This type is one for which we cannot list constructors, like `str` or `f64`. @@ -2012,11 +2023,7 @@ impl<'tcx> MissingConstructors<'tcx> { /// List the patterns corresponding to the missing constructors. In some cases, instead of /// listing all constructors of a given type, we prefer to simply report a wildcard. - fn report_patterns<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - is_top_level: bool, - ) -> SmallVec<[Pat<'tcx>; 1]> { + fn report_patterns<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Pat<'tcx>; 1]> { // There are 2 ways we can report a witness here. // Commonly, we can report all the "free" // constructors as witnesses, e.g., if we have: @@ -2044,7 +2051,7 @@ impl<'tcx> MissingConstructors<'tcx> { // `used_ctors` is empty. // The exception is: if we are at the top-level, for example in an empty match, we // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = is_top_level && !IntRange::is_integral(pcx.ty); + let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); if self.used_ctors.is_empty() && !report_when_all_missing { // All constructors are unused. Report only a wildcard // rather than each individual constructor. @@ -2086,7 +2093,7 @@ impl<'tcx> MissingConstructors<'tcx> { /// `is_under_guard` is used to inform if the pattern has a guard. If it /// has one it must not be inserted into the matrix. This shouldn't be /// relied on for soundness. -crate fn is_useful<'p, 'tcx>( +fn is_useful<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, @@ -2200,7 +2207,7 @@ crate fn is_useful<'p, 'tcx>( // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); - let pcx = PatCtxt { cx, matrix, ty, span: v.head().span }; + let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level }; debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); @@ -2215,7 +2222,7 @@ crate fn is_useful<'p, 'tcx>( let v = v.pop_head_constructor(&ctor_wild_subpatterns); let usefulness = is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns, is_top_level) + usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) }) .find(|result| result.is_useful()) .unwrap_or(NotUseful); @@ -2283,3 +2290,63 @@ fn pat_constructor<'p, 'tcx>( PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), } } + +/// The arm of a match expression. +#[derive(Clone, Copy)] +crate struct MatchArm<'p, 'tcx> { + /// The pattern must have been lowered through `MatchVisitor::lower_pattern`. + crate pat: &'p super::Pat<'tcx>, + crate hir_id: HirId, + crate has_guard: bool, +} + +/// The output of checking a match for exhaustiveness and arm reachability. +crate struct UsefulnessReport<'p, 'tcx> { + /// For each arm of the input, whether that arm is reachable after the arms above it. + crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>, + /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of + /// exhaustiveness. + crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>, +} + +/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which +/// of its arms are reachable. +/// +/// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`. +crate fn compute_match_usefulness<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + arms: &[MatchArm<'p, 'tcx>], + scrut_hir_id: HirId, + scrut_ty: Ty<'tcx>, +) -> UsefulnessReport<'p, 'tcx> { + let mut matrix = Matrix::empty(); + let arm_usefulness: Vec<_> = arms + .iter() + .copied() + .map(|arm| { + let v = PatStack::from_pattern(arm.pat); + let usefulness = + is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true); + if !arm.has_guard { + matrix.push(v); + } + (arm, usefulness) + }) + .collect(); + + let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty)); + let v = PatStack::from_pattern(wild_pattern); + let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true); + let non_exhaustiveness_witnesses = match usefulness { + NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive. + UsefulWithWitness(pats) => { + if pats.is_empty() { + bug!("Exhaustiveness check returned no witnesses") + } else { + pats.into_iter().map(|w| w.single_pattern()).collect() + } + } + Useful(_) => bug!(), + }; + UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 14ed93f1127..f9fe261bcee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,6 +1,7 @@ use super::_match::Usefulness::*; -use super::_match::WitnessPreference::*; -use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}; +use super::_match::{ + compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport, +}; use super::{PatCtxt, PatKind, PatternError}; use rustc_arena::TypedArena; @@ -12,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::nightly_options; use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; use rustc_session::parse::feature_err; @@ -170,39 +170,50 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let mut have_errors = false; - let inlined_arms: Vec<_> = arms + let arms: Vec<_> = arms .iter() - .map(|hir::Arm { pat, guard, .. }| { - (self.lower_pattern(&mut cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some()) + .map(|hir::Arm { pat, guard, .. }| MatchArm { + pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0, + hir_id: pat.hir_id, + has_guard: guard.is_some(), }) .collect(); - // Bail out early if inlining failed. + // Bail out early if lowering failed. if have_errors { return; } - // Fourth, check for unreachable arms. - let matrix = check_arms(&mut cx, &inlined_arms, source); + let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); + let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); + + // Report unreachable arms. + report_arm_reachability(&cx, &report, source); - // Fifth, check if the match is exhaustive. + // Check if the match is exhaustive. // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, // since an empty matrix can occur when there are arms, if those arms all have guards. - let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); - let is_empty_match = inlined_arms.is_empty(); - check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match); + let is_empty_match = arms.is_empty(); + let witnesses = report.non_exhaustiveness_witnesses; + if !witnesses.is_empty() { + non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match); + } } fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) { let mut cx = self.new_cx(pat.hir_id); let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false); - let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect(); - - let witnesses = match check_not_useful(&mut cx, pattern_ty, &pats, pat.hir_id) { - Ok(_) => return, - Err(err) => err, - }; + let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty); + + // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We + // only care about exhaustiveness here. + let witnesses = report.non_exhaustiveness_witnesses; + if witnesses.is_empty() { + // The pattern is irrefutable. + return; + } let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = struct_span_err!( @@ -355,17 +366,15 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir:: }); } -/// Check for unreachable patterns. -fn check_arms<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - arms: &[(&'p super::Pat<'tcx>, HirId, bool)], +/// Report unreachable arms, if any. +fn report_arm_reachability<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + report: &UsefulnessReport<'p, 'tcx>, source: hir::MatchSource, -) -> Matrix<'p, 'tcx> { - let mut seen = Matrix::empty(); +) { let mut catchall = None; - for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() { - let v = PatStack::from_pattern(pat); - match is_useful(cx, &seen, &v, LeaveOutWitness, id, has_guard, true) { + for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() { + match is_useful { NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(), @@ -374,15 +383,15 @@ fn check_arms<'p, 'tcx>( // Check which arm we're on. match arm_index { // The arm with the user-specified pattern. - 0 => unreachable_pattern(cx.tcx, pat.span, id, None), + 0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None), // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source), + 1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source), _ => bug!(), } } hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - unreachable_pattern(cx.tcx, pat.span, id, catchall); + unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall); } // Unreachable patterns in try and await expressions occur when one of @@ -390,79 +399,32 @@ fn check_arms<'p, 'tcx>( hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } + Useful(unreachables) if unreachables.is_empty() => {} + // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Useful(unreachables) => { - let mut unreachables: Vec<_> = unreachables.into_iter().flatten().collect(); + let mut unreachables: Vec<_> = unreachables.iter().flatten().copied().collect(); // Emit lints in the order in which they occur in the file. unreachables.sort_unstable(); for span in unreachables { - unreachable_pattern(cx.tcx, span, id, None); + unreachable_pattern(cx.tcx, span, arm.hir_id, None); } } UsefulWithWitness(_) => bug!(), } - if !has_guard { - seen.push(v); - if catchall.is_none() && pat_is_catchall(pat) { - catchall = Some(pat.span); - } + if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { + catchall = Some(arm.pat.span); } } - seen } -fn check_not_useful<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - ty: Ty<'tcx>, - matrix: &Matrix<'p, 'tcx>, - hir_id: HirId, -) -> Result<(), Vec<super::Pat<'tcx>>> { - let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty)); - let v = PatStack::from_pattern(wild_pattern); - - // false is given for `is_under_guard` argument due to the wildcard - // pattern not having a guard - match is_useful(cx, matrix, &v, ConstructWitness, hir_id, false, true) { - NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. - UsefulWithWitness(pats) => Err(if pats.is_empty() { - bug!("Exhaustiveness check returned no witnesses") - } else { - pats.into_iter().map(|w| w.single_pattern()).collect() - }), - Useful(_) => bug!(), - } -} - -fn check_exhaustive<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, +/// Report that a match is not exhaustive. +fn non_exhaustive_match<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - matrix: &Matrix<'p, 'tcx>, - hir_id: HirId, + witnesses: Vec<super::Pat<'tcx>>, is_empty_match: bool, ) { - // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by - // `is_useful` to exhaustively match uninhabited types, so we manually check here. - if is_empty_match && !cx.tcx.features().exhaustive_patterns { - let scrutinee_is_visibly_uninhabited = match scrut_ty.kind() { - ty::Never => true, - ty::Adt(def, _) => { - def.is_enum() - && def.variants.is_empty() - && !cx.is_foreign_non_exhaustive_enum(scrut_ty) - } - _ => false, - }; - if scrutinee_is_visibly_uninhabited { - // If the type *is* uninhabited, an empty match is vacuously exhaustive. - return; - } - } - - let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) { - Ok(_) => return, - Err(err) => err, - }; - let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(), _ => false, @@ -502,7 +464,7 @@ fn check_exhaustive<'p, 'tcx>( so a wildcard `_` is necessary to match exhaustively", scrut_ty, )); - if nightly_options::is_nightly_build() { + if cx.tcx.sess.is_nightly_build() { err.help(&format!( "add `#![feature(precise_pointer_size_matching)]` \ to the crate attributes to enable precise `{}` matching", diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6370f8c375b..32fc0f008e9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -18,6 +18,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). + #[instrument(skip(self))] pub(super) fn const_to_pat( &self, cv: &'tcx ty::Const<'tcx>, @@ -25,15 +26,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, mir_structural_match_violation: bool, ) -> Pat<'tcx> { - debug!("const_to_pat: cv={:#?} id={:?}", cv, id); - debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - let pat = self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) }); - debug!("const_to_pat: pat={:?}", pat); + debug!(?pat); pat } } @@ -61,6 +59,8 @@ struct ConstToPat<'a, 'tcx> { infcx: InferCtxt<'a, 'tcx>, include_lint_checks: bool, + + treat_byte_string_as_slice: bool, } mod fallback_to_const_ref { @@ -88,6 +88,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { span: Span, infcx: InferCtxt<'a, 'tcx>, ) -> Self { + trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { id, span, @@ -97,6 +98,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { saw_const_match_error: Cell::new(false), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), + treat_byte_string_as_slice: pat_ctxt + .typeck_results + .treat_byte_string_as_slice + .contains(&id.local_id), } } @@ -153,6 +158,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool, ) -> Pat<'tcx> { + trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be // invoked except by this method. @@ -384,7 +390,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } PatKind::Wild } - // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // `&str` is represented as `ConstValue::Slice`, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: cv }, // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when @@ -393,11 +399,33 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // as slices. This means we turn `&[T; N]` constants into slice patterns, which // has no negative effects on pattern matching, even if we're actually matching on // arrays. - ty::Array(..) | + ty::Array(..) if !self.treat_byte_string_as_slice => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Array { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::<Result<_, _>>()?, + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + ty::Array(elem_ty, _) | // Cannot merge this with the catch all branch below, because the `const_deref` // changes the type from slice to array, we need to keep the original type in the // pattern. - ty::Slice(..) => { + ty::Slice(elem_ty) => { let old = self.behind_reference.replace(true); let array = tcx.deref_const(self.param_env.and(cv)); let val = PatKind::Deref { @@ -413,7 +441,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { suffix: vec![], }), span, - ty: pointee_ty, + ty: tcx.mk_slice(elem_ty), }, }; self.behind_reference.set(old); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 188bf227c42..ffbf786491d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> { self.parse_yield_expr(attrs) } else if self.eat_keyword(kw::Let) { self.parse_let_expr(attrs) + } else if self.eat_keyword(kw::Underscore) { + self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span); + Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs)) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index b24c62b971a..e37c6418eb8 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -15,7 +15,6 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; @@ -145,7 +144,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This // is a pretty narrow case, however. - if nightly_options::is_nightly_build() { + if tcx.sess.is_nightly_build() { for gate in missing_secondary { let note = format!( "add `#![feature({})]` to the crate attributes to enable", diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7288015e170..debb873beb9 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -317,10 +317,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // swap in a new set of IR maps for this body let mut maps = IrMaps::new(self.tcx); let hir_id = maps.tcx.hir().body_owner(body.id()); - let def_id = maps.tcx.hir().local_def_id(hir_id); + let local_def_id = maps.tcx.hir().local_def_id(hir_id); + let def_id = local_def_id.to_def_id(); // Don't run unused pass for #[derive()] - if let Some(parent) = self.tcx.parent(def_id.to_def_id()) { + if let Some(parent) = self.tcx.parent(def_id) { if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) { if self.tcx.has_attr(parent, sym::automatically_derived) { return; @@ -328,8 +329,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } } - if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) { - for (&var_hir_id, _upvar) in upvars { + if let Some(captures) = maps.tcx.typeck(local_def_id).closure_captures.get(&def_id) { + for &var_hir_id in captures.keys() { let var_name = maps.tcx.hir().name(var_hir_id); maps.add_variable(Upvar(var_hir_id, var_name)); } @@ -340,7 +341,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { intravisit::walk_body(&mut maps, body); // compute liveness - let mut lsets = Liveness::new(&mut maps, def_id); + let mut lsets = Liveness::new(&mut maps, local_def_id); let entry_ln = lsets.compute(&body, hir_id); lsets.log_liveness(entry_ln, body.id().hir_id); @@ -397,10 +398,18 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // construction site. let mut call_caps = Vec::new(); let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { + if let Some(captures) = self + .tcx + .typeck(closure_def_id) + .closure_captures + .get(&closure_def_id.to_def_id()) + { + // If closure captures is Some, upvars_mentioned must also be Some + let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap(); + call_caps.extend(captures.keys().map(|var_id| { + let upvar = upvars[var_id]; let upvar_ln = self.add_live_node(UpvarNode(upvar.span)); - CaptureInfo { ln: upvar_ln, var_hid: var_id } + CaptureInfo { ln: upvar_ln, var_hid: *var_id } })); } self.set_captures(expr.hir_id, call_caps); @@ -564,6 +573,7 @@ struct Liveness<'a, 'tcx> { typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>, + closure_captures: Option<&'tcx FxIndexMap<hir::HirId, ty::UpvarId>>, successors: IndexVec<LiveNode, Option<LiveNode>>, rwu_table: RWUTable, @@ -587,6 +597,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); let param_env = ir.tcx.param_env(body_owner); let upvars = ir.tcx.upvars_mentioned(body_owner); + let closure_captures = typeck_results.closure_captures.get(&body_owner.to_def_id()); let closure_ln = ir.add_live_node(ClosureNode); let exit_ln = ir.add_live_node(ExitNode); @@ -600,6 +611,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { typeck_results, param_env, upvars, + closure_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: RWUTable::new(num_live_nodes * num_vars), closure_ln, @@ -850,14 +862,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // if they are live on the entry to the closure, since only the closure // itself can access them on subsequent calls. - if let Some(upvars) = self.upvars { + if let Some(closure_captures) = self.closure_captures { // Mark upvars captured by reference as used after closure exits. - for (&var_hir_id, upvar) in upvars.iter().rev() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.body_owner, - }; - match self.typeck_results.upvar_capture(upvar_id) { + // Since closure_captures is Some, upvars must exists too. + let upvars = self.upvars.unwrap(); + for (&var_hir_id, upvar_id) in closure_captures { + let upvar = upvars[&var_hir_id]; + match self.typeck_results.upvar_capture(*upvar_id) { ty::UpvarCapture::ByRef(_) => { let var = self.variable(var_hir_id, upvar.span); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); @@ -869,7 +880,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let succ = self.propagate_through_expr(&body.value, self.exit_ln); - if self.upvars.is_none() { + if self.closure_captures.is_none() { // Either not a closure, or closure without any captured variables. // No need to determine liveness of captured variables, since there // are none. @@ -1341,7 +1352,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { acc: u32, ) -> LiveNode { match path.res { - Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span), + Res::Local(hid) => { + let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid)); + let in_captures = self.closure_captures.map_or(false, |c| c.contains_key(&hid)); + + match (in_upvars, in_captures) { + (false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span), + (true, false) => { + // This case is possible when with RFC-2229, a wild pattern + // is used within a closure. + // eg: `let _ = x`. The closure doesn't capture x here, + // even though it's mentioned in the closure. + succ + } + } + } _ => succ, } } @@ -1531,11 +1556,15 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { - let upvars = match self.upvars { + let closure_captures = match self.closure_captures { None => return, - Some(upvars) => upvars, + Some(closure_captures) => closure_captures, }; - for (&var_hir_id, upvar) in upvars.iter() { + + // If closure_captures is Some(), upvars must be Some() too. + let upvars = self.upvars.unwrap(); + for &var_hir_id in closure_captures.keys() { + let upvar = upvars[&var_hir_id]; let var = self.variable(var_hir_id, upvar.span); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 75d75433f1b..4a0d356d337 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -4,6 +4,7 @@ #![feature(or_patterns)] #![feature(control_flow_enum)] #![feature(try_blocks)] +#![feature(associated_type_defaults)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -44,6 +45,8 @@ use std::{cmp, fmt, mem}; /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. trait DefIdVisitor<'tcx> { + type BreakTy = (); + fn tcx(&self) -> TyCtxt<'tcx>; fn shallow(&self) -> bool { false @@ -56,7 +59,7 @@ trait DefIdVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()>; + ) -> ControlFlow<Self::BreakTy>; /// Not overridden, but used to actually visit types and traits. fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { @@ -66,13 +69,16 @@ trait DefIdVisitor<'tcx> { dummy: Default::default(), } } - fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> { + fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<Self::BreakTy> { ty_fragment.visit_with(&mut self.skeleton()) } - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> { self.skeleton().visit_trait(trait_ref) } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow<Self::BreakTy> { self.skeleton().visit_predicates(predicates) } } @@ -87,13 +93,13 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> { let TraitRef { def_id, substs } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> { match predicate.skip_binders() { ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => { self.visit_trait(trait_ref) @@ -119,7 +125,10 @@ where } } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow<V::BreakTy> { let ty::GenericPredicates { parent: _, predicates } = predicates; predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) } @@ -129,7 +138,9 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = V::BreakTy; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. match *ty.kind() { @@ -283,7 +294,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow<Self::BreakTy> { self.min = VL::new_min(self, def_id); ControlFlow::CONTINUE } @@ -902,7 +913,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow<Self::BreakTy> { if let Some(def_id) = def_id.as_local() { if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = (self.tcx().visibility(def_id.to_def_id()), self.access_level) @@ -1299,7 +1310,7 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow<Self::BreakTy> { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { @@ -1799,7 +1810,7 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow<Self::BreakTy> { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 34145c3c138..493b9f15271 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1163,9 +1163,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); - let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)); - self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope); - scope + self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 00e6d5ca381..2473436a916 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,7 +16,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -890,7 +889,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { + if self.r.session.is_nightly_build() { let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \ `type` alias"; if let Some(span) = self.def_span(def_id) { @@ -1675,7 +1674,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => {} } } - if nightly_options::is_nightly_build() + if self.tcx.sess.is_nightly_build() && !self.tcx.features().in_band_lifetimes && suggests_in_band { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4e85c88c0e5..d18335ef2e6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -976,9 +976,6 @@ pub struct Resolver<'a> { /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>, - /// References to all `MacroRulesScope::Invocation(invoc_id)`s, used to update such scopes - /// when their corresponding `invoc_id`s get expanded. - invocation_macro_rules_scopes: FxHashMap<ExpnId, FxHashSet<MacroRulesScopeRef<'a>>>, /// Helper attributes that are in scope for the given expansion. helper_attrs: FxHashMap<ExpnId, Vec<Ident>>, @@ -1310,7 +1307,6 @@ impl<'a> Resolver<'a> { non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)], invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), - invocation_macro_rules_scopes: Default::default(), helper_attrs: Default::default(), local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), @@ -1680,7 +1676,20 @@ impl<'a> Resolver<'a> { !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) } Scope::DeriveHelpersCompat => true, - Scope::MacroRules(..) => true, + Scope::MacroRules(macro_rules_scope) => { + // Use "path compression" on `macro_rules` scope chains. This is an optimization + // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. + // As another consequence of this optimization visitors never observe invocation + // scopes for macros that were already expanded. + while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { + if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { + macro_rules_scope.set(next_scope.get()); + } else { + break; + } + } + true + } Scope::CrateRoot => true, Scope::Module(..) => true, Scope::RegisteredAttrs => use_prelude, @@ -1716,11 +1725,9 @@ impl<'a> Resolver<'a> { MacroRulesScope::Binding(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } - MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules( - self.output_macro_rules_scopes.get(&invoc_id).cloned().unwrap_or_else( - || self.invocation_parent_scopes[&invoc_id].macro_rules, - ), - ), + MacroRulesScope::Invocation(invoc_id) => { + Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) + } MacroRulesScope::Empty => Scope::Module(module), }, Scope::CrateRoot => match ns { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6bc9419ea84..21e43be2045 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -62,8 +62,8 @@ pub enum MacroRulesScope<'a> { } /// `macro_rules!` scopes are always kept by reference and inside a cell. -/// The reason is that we update all scopes with value `MacroRulesScope::Invocation(invoc_id)` -/// in-place immediately after `invoc_id` gets expanded. +/// The reason is that we update scopes with value `MacroRulesScope::Invocation(invoc_id)` +/// in-place after `invoc_id` gets expanded. /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow lineraly with the number of macro invocations /// in a module (including derives) and hurt performance. @@ -173,22 +173,6 @@ impl<'a> ResolverExpand for Resolver<'a> { let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - // Update all `macro_rules` scopes referring to this invocation. This is an optimization - // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. - if let Some(invocation_scopes) = self.invocation_macro_rules_scopes.remove(&expansion) { - for invocation_scope in &invocation_scopes { - invocation_scope.set(output_macro_rules_scope.get()); - } - // All `macro_rules` scopes that previously referred to `expansion` - // are now rerouted to its output scope, if it's also an invocation. - if let MacroRulesScope::Invocation(invoc_id) = output_macro_rules_scope.get() { - self.invocation_macro_rules_scopes - .entry(invoc_id) - .or_default() - .extend(invocation_scopes); - } - } - parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); } @@ -687,11 +671,7 @@ impl<'a> Resolver<'a> { { Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) } - MacroRulesScope::Invocation(invoc_id) - if !this.output_macro_rules_scopes.contains_key(&invoc_id) => - { - Err(Determinacy::Undetermined) - } + MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), }, Scope::CrateRoot => { @@ -1054,6 +1034,7 @@ impl<'a> Resolver<'a> { depr.suggestion, lint, span, + node_id, ); } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 87687339370..db16a90cc60 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1250,7 +1250,7 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition { None => DEFAULT_EDITION, }; - if !edition.is_stable() && !nightly_options::is_nightly_build() { + if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) { early_error( ErrorOutputType::default(), &format!( @@ -1547,7 +1547,9 @@ fn parse_libs( ); } }; - if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() { + if kind == NativeLibKind::StaticNoBundle + && !nightly_options::match_is_nightly_build(matches) + { early_error( error_format, "the library kind 'static-nobundle' is only \ @@ -1836,10 +1838,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { cg, error_format, externs, + unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), crate_name, alt_std_name: None, libs, - unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, trimmed_def_paths: TrimmedDefPaths::default(), @@ -1960,17 +1962,21 @@ pub mod nightly_options { use rustc_feature::UnstableFeatures; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { - is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") + match_is_nightly_build(matches) + && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") } - pub fn is_nightly_build() -> bool { - UnstableFeatures::from_environment().is_nightly_build() + pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { + is_nightly_build(matches.opt_str("crate-name").as_deref()) + } + + pub fn is_nightly_build(krate: Option<&str>) -> bool { + UnstableFeatures::from_environment(krate).is_nightly_build() } pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) { let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); - let really_allows_unstable_options = - UnstableFeatures::from_environment().is_nightly_build(); + let really_allows_unstable_options = match_is_nightly_build(matches); for opt in flags.iter() { if opt.stability == OptionStability::Stable { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 6f10d0c4b89..66c3738fb5b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -4,7 +4,7 @@ use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{Lock, Lrc, OnceCell}; +use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{error_code, Applicability, DiagnosticBuilder}; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; @@ -129,7 +129,6 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>, - pub injected_crate_name: OnceCell<Symbol>, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. @@ -150,7 +149,7 @@ impl ParseSess { pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self { Self { span_diagnostic: handler, - unstable_features: UnstableFeatures::from_environment(), + unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, raw_identifier_spans: Lock::new(Vec::new()), @@ -158,7 +157,6 @@ impl ParseSess { source_map, buffered_lints: Lock::new(vec![]), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - injected_crate_name: OnceCell::new(), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 98b7f03df38..419d1447764 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -745,6 +745,9 @@ impl Session { pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options } + pub fn is_nightly_build(&self) -> bool { + self.opts.unstable_features.is_nightly_build() + } pub fn overflow_checks(&self) -> bool { self.opts .cg diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ad58f89d87d..3a2a3adce35 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -318,6 +318,7 @@ symbols! { call_mut, call_once, caller_location, + capture_disjoint_fields, cdylib, ceilf32, ceilf64, @@ -909,6 +910,7 @@ symbols! { rustc_args_required_const, rustc_attrs, rustc_builtin_macro, + rustc_capture_analysis, rustc_clean, rustc_const_stable, rustc_const_unstable, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index ac91fcf6293..eba8e1a0613 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -51,7 +51,7 @@ pub(super) fn mangle( // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); + let instance_ty = tcx.erase_regions(instance_ty); let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 822a8352934..a28c8cac728 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -39,7 +39,7 @@ impl SymbolNamesTest<'tcx> { let def_id = def_id.to_def_id(); let instance = Instance::new( def_id, - tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)), + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)), ); let mangled = tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index b9c5123e49a..05b6c4a48de 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { param_env, state: AutoderefSnapshot { steps: vec![], - cur_ty: infcx.resolve_vars_if_possible(&base_ty), + cur_ty: infcx.resolve_vars_if_possible(base_ty), obligations: vec![], at_start: true, reached_recursion_limit: false, @@ -164,14 +164,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); - Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) + Some(self.infcx.resolve_vars_if_possible(normalized_ty)) } /// Returns the final type we ended up with, which may be an inference /// variable (we will resolve it first, if we want). pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { if resolve { - self.infcx.resolve_vars_if_possible(&self.state.cur_ty) + self.infcx.resolve_vars_if_possible(self.state.cur_ty) } else { self.state.cur_ty } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 4ec1b29bca4..41184ce2116 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -28,7 +28,7 @@ pub trait InferCtxtExt<'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>; @@ -41,7 +41,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ty: Ty<'tcx>, span: Span, ) -> bool { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); @@ -63,7 +63,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>, @@ -173,7 +173,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { debug!("add_implied_bounds()"); for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(&ty); + let ty = infcx.resolve_vars_if_possible(ty); debug!("add_implied_bounds: ty = {}", ty); let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); self.add_outlives_bounds(Some(infcx), implied_bounds) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 914fa1e52c2..ca547bf88b5 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -12,7 +12,6 @@ use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::nightly_options; use rustc_span::Span; use std::ops::ControlFlow; @@ -113,7 +112,7 @@ pub trait InferCtxtExt<'tcx> { parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, value_span: Span, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; @@ -189,7 +188,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, value_span: Span, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { debug!( @@ -403,7 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let tcx = self.tcx; - let concrete_ty = self.resolve_vars_if_possible(&opaque_defn.concrete_ty); + let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); @@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; err.span_label(span, label); - if nightly_options::is_nightly_build() { + if self.tcx.sess.is_nightly_build() { err.help("add #![feature(member_constraints)] to the crate attributes to enable"); } @@ -693,12 +692,15 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &ty::Binder<T>, + ) -> ControlFlow<Self::BreakTy> { t.as_ref().skip_binder().visit_with(self); ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { match *r { // ignore bound regions, keep visiting ty::ReLateBound(_, _) => ControlFlow::CONTINUE, @@ -709,7 +711,7 @@ where } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { return ControlFlow::CONTINUE; @@ -1002,7 +1004,7 @@ struct Instantiator<'a, 'tcx> { } impl<'a, 'tcx> Instantiator<'a, 'tcx> { - fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { + fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { debug!("instantiate_opaque_types_in_map(value={:?})", value); let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { @@ -1126,7 +1128,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let param_env = tcx.param_env(def_id); let InferOk { value: bounds, obligations } = - infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds); + infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, bounds); self.obligations.extend(obligations); debug!("instantiate_opaque_types: bounds={:?}", bounds); @@ -1174,7 +1176,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Change the predicate to refer to the type variable, // which will be the concrete type instead of the opaque type. // This also instantiates nested instances of `impl Trait`. - let predicate = self.instantiate_opaque_types_in_map(&predicate); + let predicate = self.instantiate_opaque_types_in_map(predicate); let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 93a0073588e..6ab16886ed2 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -304,11 +304,8 @@ impl AutoTraitFinder<'tcx> { // Call `infcx.resolve_vars_if_possible` to see if we can // get rid of any inference variables. - let obligation = infcx.resolve_vars_if_possible(&Obligation::new( - dummy_cause.clone(), - new_env, - pred, - )); + let obligation = + infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred)); let result = select.select(&obligation); match &result { @@ -627,7 +624,7 @@ impl AutoTraitFinder<'tcx> { fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate)); // Resolve any inference variables that we can, to help selection succeed - let predicate = select.infcx().resolve_vars_if_possible(&obligation.predicate); + let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate); // We only add a predicate as a user-displayable bound if // it involves a generic parameter, and doesn't contain diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index adc8ae59086..026ab414443 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -37,7 +37,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { obligation: PredicateObligation<'tcx>, ) { assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); self.obligations.insert(obligation); } @@ -80,11 +80,11 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { // We iterate over all obligations, and record if we are able // to unambiguously prove at least one obligation. for obligation in self.obligations.drain(..) { - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); let environment = obligation.param_env.caller_bounds(); let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values); + let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { @@ -100,7 +100,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { Ok(infer_ok) => next_round.extend( infer_ok.obligations.into_iter().map(|obligation| { assert!(!infcx.is_in_snapshot()); - infcx.resolve_vars_if_possible(&obligation) + infcx.resolve_vars_if_possible(obligation) }), ), diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 3cb6ec86261..657d5c123e8 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -25,7 +25,7 @@ pub fn codegen_fulfill_obligation<'tcx>( (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result<ImplSource<'tcx, ()>, ErrorReported> { // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); + let trait_ref = tcx.erase_regions(trait_ref); // We expect the input to be fully normalized. debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); debug!( @@ -89,7 +89,7 @@ pub fn codegen_fulfill_obligation<'tcx>( debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source); + let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); info!("Cache miss: {:?} => {:?}", trait_ref, impl_source); Ok(impl_source) @@ -110,7 +110,7 @@ pub fn codegen_fulfill_obligation<'tcx>( fn drain_fulfillment_cx_or_panic<T>( infcx: &InferCtxt<'_, 'tcx>, fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, + result: T, ) -> T where T: TypeFoldable<'tcx>, @@ -128,5 +128,5 @@ where } let result = infcx.resolve_vars_if_possible(result); - infcx.tcx.erase_regions(&result) + infcx.tcx.erase_regions(result) } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index c53c65c00b7..9324d55ac1b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -103,7 +103,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>( }; let Normalized { value: mut header, obligations } = - traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); + traits::normalize(selcx, param_env, ObligationCause::dummy(), header); header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); header @@ -162,7 +162,8 @@ fn overlap_within_probe( let opt_failing_obligation = a_impl_header .predicates .iter() - .chain(&b_impl_header.predicates) + .copied() + .chain(b_impl_header.predicates) .map(|p| infcx.resolve_vars_if_possible(p)) .map(|p| Obligation { cause: ObligationCause::dummy(), @@ -188,7 +189,7 @@ fn overlap_within_probe( } } - let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); + let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header); let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e1721a5a88a..fdb2361ba03 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -78,7 +78,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const(tcx, ct, |node| match node { + walk_abstract_const::<!, _>(tcx, ct, |node| match node { Node::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { @@ -574,19 +574,19 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -pub fn walk_abstract_const<'tcx, F>( +pub fn walk_abstract_const<'tcx, R, F>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F, -) -> ControlFlow<()> +) -> ControlFlow<R> where - F: FnMut(Node<'tcx>) -> ControlFlow<()>, + F: FnMut(Node<'tcx>) -> ControlFlow<R>, { - fn recurse<'tcx>( + fn recurse<'tcx, R>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>, - ) -> ControlFlow<()> { + f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<R>, + ) -> ControlFlow<R> { let root = ct.root(); f(root)?; match root { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 2d57c39f7c7..d429d889fcc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { where T: fmt::Display + TypeFoldable<'tcx>, { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); let mut err = struct_span_err!( self.tcx.sess, obligation.cause.span, @@ -213,7 +213,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// we do not suggest increasing the overflow limit, which is not /// going to help). fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); + let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); debug!("report_overflow_error_cycle: cycle={:?}", cycle); @@ -259,7 +259,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(trait_predicate, _) => { let trait_predicate = bound_predicate.rebind(trait_predicate); - let trait_predicate = self.resolve_vars_if_possible(&trait_predicate); + let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { return; @@ -414,17 +414,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(enclosing_scope_span, s.as_str()); } - self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_remove_reference(&obligation, &mut err, &trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); + self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg); + self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg); + self.suggest_remove_reference(&obligation, &mut err, trait_ref); + self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref); self.note_version_mismatch(&mut err, &trait_ref); if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { - self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + self.suggest_await_before_try(&mut err, &obligation, trait_ref, span); } - if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { + if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) { err.emit(); return; } @@ -487,7 +487,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_change_mut( &obligation, &mut err, - &trait_ref, + trait_ref, points_at_arg, ); } @@ -533,7 +533,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateAtom::RegionOutlives(predicate) => { let predicate = bound_predicate.rebind(predicate); - let predicate = self.resolve_vars_if_possible(&predicate); + let predicate = self.resolve_vars_if_possible(predicate); let err = self .region_outlives_predicate(&obligation.cause, predicate) .err() @@ -549,7 +549,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); struct_span_err!( self.tcx.sess, span, @@ -671,9 +671,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); + OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => { + let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); + let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); if expected_trait_ref.self_ty().references_error() { return; @@ -1035,7 +1035,7 @@ trait InferCtxtPrivExt<'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx>; @@ -1157,7 +1157,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); if predicate.references_error() { return; @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let (data, _) = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, - &bound_predicate.rebind(data), + bound_predicate.rebind(data), ); let mut obligations = vec![]; let normalized_ty = super::normalize_projection_type( @@ -1343,7 +1343,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // Sort impl candidates so that ordering is consistent for UI tests. let mut normalized_impl_candidates = - impl_candidates.iter().map(normalize).collect::<Vec<String>>(); + impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>(); // Sort before taking the `..end` range, // because the ordering of `impl_candidates` may not be deterministic: @@ -1364,7 +1364,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> Option<(String, Option<Span>)> { match code { &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), None => { @@ -1414,7 +1414,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx> { assert!(!new_self_ty.has_escaping_bound_vars()); @@ -1441,7 +1441,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // ambiguous impls. The latter *ought* to be a // coherence violation, so we don't report it here. - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; debug!( @@ -1673,7 +1673,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { &mut selcx, param_env, ObligationCause::dummy(), - &cleaned_pred, + cleaned_pred, ) .value; @@ -1808,7 +1808,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, ) -> bool { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { return true; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 0f5aad5af12..1b5375938af 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> Option<DefId> { let tcx = self.tcx; let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(&trait_ref); + let trait_ref = tcx.erase_late_bound_regions(trait_ref); let trait_self_ty = trait_ref.self_ty(); let mut self_match_impls = vec![]; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1c6e661782f..7e92df28ca2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -49,7 +49,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, points_at_arg: bool, ); @@ -64,7 +64,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, points_at_arg: bool, ); @@ -81,14 +81,14 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ); fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, points_at_arg: bool, ); @@ -97,7 +97,7 @@ pub trait InferCtxtExt<'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ); fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; @@ -107,7 +107,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ) -> bool; fn point_at_returns_when_relevant( @@ -168,7 +168,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, span: Span, ); } @@ -462,7 +462,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, points_at_arg: bool, ) { // It only make sense when suggesting dereferences for arguments @@ -475,7 +475,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let real_trait_ref = match &obligation.cause.code { ObligationCauseCode::ImplDerivedObligation(cause) | ObligationCauseCode::DerivedObligation(cause) - | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref, + | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref, _ => trait_ref, }; let real_ty = match real_trait_ref.self_ty().no_bound_vars() { @@ -556,7 +556,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, points_at_arg: bool, ) { let self_ty = match trait_ref.self_ty().no_bound_vars() { @@ -734,7 +734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ) { let span = obligation.cause.span; @@ -797,7 +797,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, points_at_arg: bool, ) { let span = obligation.cause.span; @@ -832,7 +832,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, - &trait_ref, + trait_ref, suggested_ty, ); let suggested_ty_would_satisfy_obligation = self @@ -869,7 +869,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ) { let is_empty_tuple = |ty: ty::Binder<Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); @@ -919,7 +919,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, ) -> bool { match obligation.cause.code.peel_derives() { // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. @@ -976,12 +976,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .returns .iter() .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) - .map(|ty| self.resolve_vars_if_possible(&ty)); + .map(|ty| self.resolve_vars_if_possible(ty)); let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( (None, true, true), |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool), ty| { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); same &= !matches!(ty.kind(), ty::Error(_)) && last_ty.map_or(true, |last_ty| { @@ -1133,7 +1133,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); for expr in &visitor.returns { if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { - let ty = self.resolve_vars_if_possible(&returned_ty); + let ty = self.resolve_vars_if_possible(returned_ty); err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); } } @@ -1406,7 +1406,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Look for a type inside the generator interior that matches the target type to get // a span. - let target_ty_erased = self.tcx.erase_regions(&target_ty); + let target_ty_erased = self.tcx.erase_regions(target_ty); let ty_matches = |ty| -> bool { // Careful: the regions for types that appear in the // generator interior are not generally known, so we @@ -1420,8 +1420,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // generator frame. Bound regions are preserved by // `erase_regions` and so we must also call // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); + let ty_erased = self.tcx.erase_late_bound_regions(ty::Binder::bind(ty)); + let ty_erased = self.tcx.erase_regions(ty_erased); let eq = ty::TyS::same_type(ty_erased, target_ty_erased); debug!( "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ @@ -1437,7 +1437,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) { interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = typeck_results.node_type(*upvar_id); - let upvar_ty = self.resolve_vars_if_possible(&upvar_ty); + let upvar_ty = self.resolve_vars_if_possible(upvar_ty); if ty_matches(&upvar_ty) { Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) } else { @@ -2010,7 +2010,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { err.cancel(); @@ -2025,8 +2025,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = *data.parent_code { - let parent_trait_ref = - self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let ty = parent_trait_ref.skip_binder().self_ty(); matches!(ty.kind(), ty::Generator(..)) || matches!(ty.kind(), ty::Closure(..)) @@ -2056,7 +2055,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); err.note(&format!( "required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref.print_only_trait_path(), @@ -2074,7 +2073,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } ObligationCauseCode::DerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); // #74711: avoid a stack overflow ensure_sufficient_stack(|| { @@ -2132,7 +2131,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<ty::TraitRef<'tcx>>, span: Span, ) { debug!( @@ -2150,13 +2149,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty()); // Do not check on infer_types to avoid panic in evaluate_obligation. if self_ty.has_infer_types() { return; } - let self_ty = self.tcx.erase_regions(&self_ty); + let self_ty = self.tcx.erase_regions(self_ty); let impls_future = self.tcx.type_implements_trait(( future_trait, @@ -2197,7 +2196,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!( "suggest_await_before_try: normalized_projection_type {:?}", - self.resolve_vars_if_possible(&normalized_ty) + self.resolve_vars_if_possible(normalized_ty) ); let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 538c14c6b72..a04f816b0f8 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -202,7 +202,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { ) { // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); debug!(?obligation, "register_predicate_obligation"); @@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { if !change { debug!( "process_predicate: pending obligation {:?} still stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation), + self.selcx.infcx().resolve_vars_if_possible(pending_obligation.obligation.clone()), pending_obligation.stalled_on ); return ProcessResult::Unchanged; @@ -338,14 +338,14 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if obligation.predicate.has_infer_types_or_consts() { obligation.predicate = - self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); + self.selcx.infcx().resolve_vars_if_possible(obligation.predicate); } debug!(?obligation, ?obligation.cause, "process_obligation"); let infcx = self.selcx.infcx(); - match obligation.predicate.kind() { + match *obligation.predicate.kind() { ty::PredicateKind::ForAll(binder) => match binder.skip_binder() { // Evaluation will discard candidates using the leak check. // This means we need to pass it the bound version of our @@ -384,9 +384,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { bug!("TypeWellFormedFromEnv is only used for Chalk") } }, - &ty::PredicateKind::Atom(atom) => match atom { - ty::PredicateAtom::Trait(ref data, _) => { - let trait_obligation = obligation.with(Binder::dummy(*data)); + ty::PredicateKind::Atom(atom) => match atom { + ty::PredicateAtom::Trait(data, _) => { + let trait_obligation = obligation.with(Binder::dummy(data)); self.process_trait_obligation( obligation, @@ -639,7 +639,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", - infcx.resolve_vars_if_possible(obligation), + infcx.resolve_vars_if_possible(obligation.clone()), stalled_on ); @@ -684,7 +684,7 @@ fn trait_ref_infer_vars<'a, 'tcx>( ) -> Vec<TyOrConstInferVar<'tcx>> { selcx .infcx() - .resolve_vars_if_possible(&trait_ref) + .resolve_vars_if_possible(trait_ref) .skip_binder() .substs .iter() diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index e23f5a583b2..cedd1aa54b8 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -50,7 +50,7 @@ pub fn can_type_implement_copy( let span = tcx.def_span(field.did); let cause = ObligationCause::dummy_with_span(span); let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { + match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c93087a18cf..2d7df2ddd11 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -223,7 +223,7 @@ fn do_normalize_predicates<'tcx>( // we move over to lazy normalization *anyway*. let fulfill_cx = FulfillmentContext::new_ignoring_regions(); let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { + match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, Err(errors) => { infcx.report_fulfillment_errors(&errors, None, false); @@ -243,7 +243,7 @@ fn do_normalize_predicates<'tcx>( RegionckMode::default(), ); - let predicates = match infcx.fully_resolve(&predicates) { + let predicates = match infcx.fully_resolve(predicates) { Ok(predicates) => predicates, Err(fixup_err) => { // If we encounter a fixup error, it means that some type @@ -384,7 +384,7 @@ pub fn fully_normalize<'a, 'tcx, T>( mut fulfill_cx: FulfillmentContext<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> Result<T, Vec<FulfillmentError<'tcx>>> where T: TypeFoldable<'tcx>, @@ -404,7 +404,7 @@ where debug!("fully_normalize: select_all_or_error start"); fulfill_cx.select_all_or_error(infcx)?; debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); + let resolved_value = infcx.resolve_vars_if_possible(normalized_value); debug!("fully_normalize: resolved_value={:?}", resolved_value); Ok(resolved_value) } @@ -424,7 +424,7 @@ pub fn impossible_predicates<'tcx>( let mut fulfill_cx = FulfillmentContext::new(); let cause = ObligationCause::dummy(); let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), &predicates); + normalize(&mut selcx, param_env, cause.clone(), predicates); for obligation in obligations { fulfill_cx.register_predicate_obligation(&infcx, obligation); } @@ -435,7 +435,7 @@ pub fn impossible_predicates<'tcx>( fulfill_cx.select_all_or_error(&infcx).is_err() }); - debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result); + debug!("impossible_predicates = {:?}", result); result } @@ -494,7 +494,7 @@ fn vtable_methods<'tcx>( // erase them if they appear, so that we get the type // at some particular call site. let substs = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs); // It's possible that the method relies on where-clauses that // do not hold for this particular set of type parameters. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 32e0991733b..d912a00d6b7 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -446,7 +446,7 @@ fn virtual_call_violation_for_method<'tcx>( } let receiver_ty = - tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); + tcx.liberate_late_bound_regions(method.def_id, sig.map_bound(|sig| sig.inputs()[0])); // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. // However, this is already considered object-safe. We allow it as a special case here. @@ -771,7 +771,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { @@ -812,7 +814,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // First check if the type of this constant references `Self`. self.visit_ty(ct.ty)?; @@ -844,7 +846,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a85ffd3c961..dead795c6af 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -168,7 +168,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|_snapshot| { let placeholder_predicate = - infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + infcx.replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation = obligation.with(placeholder_predicate); let result = project_and_unify_type(selcx, &placeholder_obligation)?; @@ -232,7 +232,7 @@ pub fn normalize<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, - value: &T, + value: T, ) -> Normalized<'tcx, T> where T: TypeFoldable<'tcx>, @@ -246,7 +246,7 @@ pub fn normalize_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, - value: &T, + value: T, obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> T where @@ -261,7 +261,7 @@ pub fn normalize_with_depth<'a, 'b, 'tcx, T>( param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize, - value: &T, + value: T, ) -> Normalized<'tcx, T> where T: TypeFoldable<'tcx>, @@ -277,7 +277,7 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize, - value: &T, + value: T, obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> T where @@ -309,7 +309,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } } - fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { + fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); if !value.has_projections() { value } else { value.fold_with(self) } @@ -365,7 +365,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { + ty::Projection(data) if !data.has_escaping_bound_vars() => { // This is kind of hacky -- we need to be able to // handle normalization within binders because // otherwise we wind up a need to normalize when doing @@ -381,7 +381,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { let normalized_ty = normalize_projection_type( self.selcx, self.param_env, - *data, + data, self.cause.clone(), self.depth, &mut self.obligations, @@ -474,7 +474,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ) -> Result<Option<Ty<'tcx>>, InProgress> { let infcx = selcx.infcx(); - let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); + let projection_ty = infcx.resolve_vars_if_possible(projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); // FIXME(#20304) For now, I am caching here, which is good, but it @@ -567,7 +567,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( depth + 1, &mut projected_obligations, ); - let normalized_ty = normalizer.fold(&projected_ty); + let normalized_ty = normalizer.fold(projected_ty); debug!(?normalized_ty, ?depth); @@ -1013,8 +1013,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( if obligation.param_env.reveal() == Reveal::All { // NOTE(eddyb) inference variables can resolve to parameters, so // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = - selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); + let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref); !poly_trait_ref.still_further_specializable() } else { debug!( @@ -1192,7 +1191,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &gen_sig, + gen_sig, ); debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); @@ -1263,7 +1262,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &sig, + sig, ); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) @@ -1282,7 +1281,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &closure_sig, + closure_sig, ); debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); @@ -1336,7 +1335,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( cause.span, LateBoundRegionConversionTime::HigherRankedType, - &poly_cache_entry, + poly_cache_entry, ); let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); @@ -1349,7 +1348,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &cache_trait_ref, + cache_trait_ref, &mut nested_obligations, ) }) @@ -1445,7 +1444,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &predicate, + predicate, nested, ); nested.push(Obligation::with_depth( @@ -1526,7 +1525,7 @@ impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { // from a specific call to `opt_normalize_projection_type` - if // there's no precise match, the original cache entry is "stranded" // anyway. - infcx.resolve_vars_if_possible(&predicate.projection_ty), + infcx.resolve_vars_if_possible(predicate.projection_ty), ) }) } diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 8212823a6db..f05582f0614 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -40,10 +40,10 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { } let mut orig_values = OriginalQueryValues::default(); - let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); + let c_ty = self.infcx.canonicalize_query(self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); - if let Ok(result) = &tcx.dropck_outlives(c_ty) { + if let Ok(result) = tcx.dropck_outlives(c_ty) { if result.is_proven() { if let Ok(InferOk { value, obligations }) = self.infcx.instantiate_query_response_and_region_obligations( @@ -53,7 +53,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { result, ) { - let ty = self.infcx.resolve_vars_if_possible(&ty); + let ty = self.infcx.resolve_vars_if_possible(ty); let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); return InferOk { value: kinds, obligations }; } diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 0569f6217da..b83a4cd1e57 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -65,7 +65,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ) -> Result<EvaluationResult, OverflowError> { let mut _orig_values = OriginalQueryValues::default(); let c_pred = self - .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); + .canonicalize_query(obligation.param_env.and(obligation.predicate), &mut _orig_values); // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 42a598ce3a0..54743ef9ce9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -19,7 +19,7 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; pub trait AtExt<'tcx> { - fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> + fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where T: TypeFoldable<'tcx>; } @@ -38,7 +38,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". - fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> + fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where T: TypeFoldable<'tcx>, { @@ -97,6 +97,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.infcx.tcx } + #[instrument(skip(self))] fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if !ty.has_projections() { return ty; @@ -145,7 +146,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } } - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { + ty::Projection(data) if !data.has_escaping_bound_vars() => { // This is kind of hacky -- we need to be able to // handle normalization within binders because // otherwise we wind up a need to normalize when doing @@ -165,7 +166,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // so we cannot canonicalize it. let c_data = self .infcx - .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); + .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); match tcx.normalize_projection_ty(c_data) { @@ -180,7 +181,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.cause, self.param_env, &orig_values, - &result, + result, ) { Ok(InferOk { value: result, obligations }) => { debug!("QueryNormalizer: result = {:#?}", result); diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs index a42409515db..f5fa52c915d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs @@ -51,7 +51,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { debug!("implied_outlives_bounds(ty = {:?})", ty); let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); + let key = self.canonicalize_query(param_env.and(ty), &mut orig_values); let result = match self.tcx.implied_outlives_bounds(key) { Ok(r) => r, Err(NoSolution) => { @@ -68,7 +68,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { &ObligationCause::misc(span, body_id), param_env, &orig_values, - &result, + result, ); debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); let result = match result { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 915e8ae4a7a..1688539165a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -96,7 +96,7 @@ fn scrape_region_constraints<'tcx, R>( region_obligations .iter() .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)), + .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index ed6c6d0cc0a..130ffa1a33a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -81,16 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { // like the subtype query, which go awry around // `'static` otherwise. let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_self = - infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); + let old_param_env = query_key.param_env; + let canonical_self = infcx.canonicalize_hr_query_hack(query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; - let param_env = query_key.param_env; - let InferOk { value, obligations } = infcx .instantiate_nll_query_response_and_region_obligations( &ObligationCause::dummy(), - param_env, + old_param_env, &canonical_var_values, canonical_result, output_query_region_constraints, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index ea18a689065..d2556c44fb4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -229,7 +229,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: obligation.param_env, cause: obligation.cause.clone(), recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), + predicate: self.infcx().resolve_vars_if_possible(obligation.predicate), }; if obligation.predicate.skip_binder().self_ty().is_ty_var() { @@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase // any LBR. - let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); + let self_ty = self.tcx().erase_late_bound_regions(obligation.self_ty()); let poly_trait_ref = match self_ty.kind() { ty::Dynamic(ref data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { @@ -639,9 +639,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?poly_trait_ref, "assemble_candidates_from_object_ty"); - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 872b8e85f56..7c155c7684e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -126,7 +126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(trait_predicate); let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let (def_id, substs) = match *placeholder_self_ty.kind() { ty::Projection(proj) => (proj.item_def_id, proj.substs), @@ -144,7 +144,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &candidate, + candidate, &mut obligations, ); @@ -163,7 +163,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &predicate, + predicate, &mut obligations, ); obligations.push(Obligation::with_depth( @@ -285,8 +285,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.commit_unconditionally(|_| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); self.impl_or_trait_obligations( cause, @@ -370,11 +369,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); - let data = match self_ty.kind() { + let data = match *self_ty.kind() { ty::Dynamic(data, ..) => { self.infcx .replace_bound_vars_with_fresh_vars( @@ -416,7 +414,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &unnormalized_upcast_trait_ref, + unnormalized_upcast_trait_ref, &mut nested, ); @@ -442,7 +440,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &super_trait, + super_trait, &mut nested, ); nested.push(Obligation::new( @@ -480,7 +478,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &subst_bound, + subst_bound, &mut nested, ); nested.push(Obligation::new( @@ -520,7 +518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); @@ -541,8 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate"); self.infcx.commit_unconditionally(|_| { - let predicate = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; @@ -584,7 +581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); @@ -627,7 +624,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a91f693f175..05ff9a6fb9c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let obligation = &stack.obligation; - let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); // Okay to skip binder because of the nature of the // trait-ref-is-knowable check, which does not care about @@ -1138,9 +1138,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> smallvec::SmallVec<[usize; 2]> { - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); debug!( ?placeholder_trait_predicate, "match_projection_obligation_against_definition_bounds" @@ -1220,7 +1220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_bound, + trait_bound, ) }); self.infcx @@ -1266,12 +1266,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &data.map_bound_ref(|data| data.projection_ty), + data.map_bound(|data| data.projection_ty), &mut nested_obligations, ) }) } else { - data.map_bound_ref(|data| data.projection_ty) + data.map_bound(|data| data.projection_ty) }; // FIXME(generic_associated_types): Compare the whole projections @@ -1737,7 +1737,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ self.infcx.commit_unconditionally(|_| { - let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(&ty); + let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -1745,7 +1745,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - &placeholder_ty, + placeholder_ty, ) }); let placeholder_obligation = predicate_for_trait_def( @@ -1807,7 +1807,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let placeholder_obligation = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); @@ -1821,7 +1821,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &impl_trait_ref, + impl_trait_ref, ) }); @@ -2028,7 +2028,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - &predicate.subst(tcx, substs), + predicate.subst(tcx, substs), &mut obligations, ); obligations.push(Obligation { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 4d81a3baa0e..512591960f5 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -158,7 +158,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, FulfillmentContext::new(), ObligationCause::dummy(), penv, - &impl1_trait_ref, + impl1_trait_ref, ) { Ok(impl1_trait_ref) => impl1_trait_ref, Err(err) => { @@ -247,7 +247,7 @@ fn fulfill_implication<'a, 'tcx>( // Now resolve the *substitution* we built for the target earlier, replacing // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(&target_substs)) + Ok(infcx.resolve_vars_if_possible(target_substs)) } } }) diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index ce0d3ef8a6a..3d20a8d5cf3 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -55,9 +55,7 @@ pub fn search_for_structural_match_violation<'tcx>( ) -> Option<NonStructuralMatchTy<'tcx>> { // FIXME: we should instead pass in an `infcx` from the outside. tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() }; - ty.visit_with(&mut search); - search.found + ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value() }) } @@ -116,9 +114,6 @@ struct Search<'a, 'tcx> { infcx: InferCtxt<'a, 'tcx>, - /// Records first ADT that does not implement a structural-match trait. - found: Option<NonStructuralMatchTy<'tcx>>, - /// Tracks ADTs previously encountered during search, so that /// we will not recur on them again. seen: FxHashSet<hir::def_id::DefId>, @@ -135,38 +130,33 @@ impl Search<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = NonStructuralMatchTy<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { - self.found = Some(NonStructuralMatchTy::Param); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Param); } ty::Dynamic(..) => { - self.found = Some(NonStructuralMatchTy::Dynamic); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Dynamic); } ty::Foreign(_) => { - self.found = Some(NonStructuralMatchTy::Foreign); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Foreign); } ty::Opaque(..) => { - self.found = Some(NonStructuralMatchTy::Opaque); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Opaque); } ty::Projection(..) => { - self.found = Some(NonStructuralMatchTy::Projection); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Projection); } ty::Generator(..) | ty::GeneratorWitness(..) => { - self.found = Some(NonStructuralMatchTy::Generator); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Generator); } ty::Closure(..) => { - self.found = Some(NonStructuralMatchTy::Closure); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Closure); } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -206,8 +196,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. - ty.super_visit_with(self); - return ControlFlow::CONTINUE; + return ty.super_visit_with(self); } ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); @@ -227,8 +216,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); - self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def)); } // structural-match does not care about the @@ -244,20 +232,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // even though we skip super_visit_with, we must recur on // fields of ADT. let tcx = self.tcx(); - for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { + adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - - if ty.visit_with(self).is_break() { - // found an ADT without structural-match; halt visiting! - assert!(self.found.is_some()); - return ControlFlow::BREAK; - } - } - - // Even though we do not want to recur on substs, we do - // want our caller to continue its own search. - ControlFlow::CONTINUE + ty.visit_with(self) + }) } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f626bb0b7e3..2430620323f 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -205,12 +205,12 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>( let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); + super::normalize(selcx, param_env, ObligationCause::dummy(), impl_trait_ref); let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); + super::normalize(selcx, param_env, ObligationCause::dummy(), predicates); let impl_obligations = predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 496dff6c5b2..e5a792f229d 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { param_env, cause.clone(), self.recursion_depth, - &obligation.predicate, + obligation.predicate, &mut obligations, ); obligation.predicate = normalized_predicate; diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index c5a46b1003d..b1b9ef343d5 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -227,7 +227,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( &self.interner, self.interner.tcx, - &sig.inputs_and_output().subst(self.interner.tcx, bound_vars), + sig.inputs_and_output().subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] @@ -461,7 +461,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> { let bound_vars = ty::fold::shift_vars( self.interner.tcx, - &bound_vars_for_item(self.interner.tcx, opaque_ty_id.0), + bound_vars_for_item(self.interner.tcx, opaque_ty_id.0), 1, ); let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index c4e2c7f839d..9afb980f84d 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -86,7 +86,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' let (predicate, binders, _named_regions) = collect_bound_vars( interner, interner.tcx, - &predicate.bound_atom_with_opt_escaping(interner.tcx), + predicate.bound_atom_with_opt_escaping(interner.tcx), ); let consequence = match predicate { ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { @@ -141,7 +141,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi let (predicate, binders, _named_regions) = collect_bound_vars( interner, interner.tcx, - &self.bound_atom_with_opt_escaping(interner.tcx), + self.bound_atom_with_opt_escaping(interner.tcx), ); let value = match predicate { @@ -293,7 +293,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { } ty::FnPtr(sig) => { let (inputs_and_outputs, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); + collect_bound_vars(interner, interner.tcx, sig.inputs_and_output()); chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), sig: sig.lower_into(interner), @@ -578,7 +578,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' let (predicate, binders, _named_regions) = collect_bound_vars( interner, interner.tcx, - &self.bound_atom_with_opt_escaping(interner.tcx), + self.bound_atom_with_opt_escaping(interner.tcx), ); let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { @@ -627,10 +627,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru // Binders<&[Binders<WhereClause<I>>]> // This means that any variables that are escaping `self` need to be // shifted in by one so that they are still escaping. - let shifted_predicates = ty::fold::shift_vars(interner.tcx, &self, 1); + let shifted_predicates = ty::fold::shift_vars(interner.tcx, self, 1); let (predicates, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &shifted_predicates); + collect_bound_vars(interner, interner.tcx, shifted_predicates); let self_ty = interner.tcx.mk_ty(ty::Bound( // This is going to be wrapped in a binder ty::DebruijnIndex::from_usize(1), @@ -707,7 +707,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru let (predicate, binders, _named_regions) = collect_bound_vars( interner, interner.tcx, - &self.bound_atom_with_opt_escaping(interner.tcx), + self.bound_atom_with_opt_escaping(interner.tcx), ); match predicate { ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new( @@ -808,10 +808,10 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx> /// It's important to note that because of prior substitution, we may have /// late-bound regions, even outside of fn contexts, since this is the best way /// to prep types for chalk lowering. -crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( +crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( interner: &RustInterner<'tcx>, tcx: TyCtxt<'tcx>, - ty: &'a Binder<T>, + ty: Binder<T>, ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) { let mut bound_vars_collector = BoundVarsCollector::new(); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); @@ -824,7 +824,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .collect(); let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters); - let new_ty = ty.as_ref().skip_binder().fold_with(&mut bound_var_substitutor); + let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor); for var in named_parameters.values() { parameters.insert(*var, chalk_ir::VariableKind::Lifetime); @@ -833,7 +833,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( (0..parameters.len()).for_each(|i| { parameters .get(&(i as u32)) - .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters)); + .or_else(|| bug!("Skipped bound var index: parameters={:?}", parameters)); }); let binders = @@ -859,14 +859,14 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { @@ -886,7 +886,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { ty::BoundRegion::BrNamed(def_id, _name) => { @@ -941,7 +941,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -1001,7 +1001,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -1076,7 +1076,7 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); @@ -1088,7 +1088,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { if let ty::BoundRegion::BrAnon(anon) = p.name { diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 6cffa6d02a4..2827163d854 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -106,7 +106,7 @@ fn dropck_outlives<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - match infcx.at(&cause, param_env).normalize(&ty) { + match infcx.at(&cause, param_env).normalize(ty) { Ok(Normalized { value: ty, obligations }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index c44fd1d5859..97017fbf2e5 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -115,7 +115,7 @@ fn compute_implied_outlives_bounds<'tcx>( } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_vars_if_possible(&ty_a); + let ty_a = infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; tcx.push_outlives_components(ty_a, &mut components); implied_bounds_from_components(r_b, components) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 3e7c9ac62eb..750a0922be4 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -21,7 +21,7 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::dummy(); - match infcx.at(&cause, param_env).normalize(&value) { + match infcx.at(&cause, param_env).normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { // We don't care about the `obligations`; they are // always only region relations, and we are about to @@ -31,8 +31,8 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( None, ); - let normalized_value = infcx.resolve_vars_if_possible(&normalized_value); - infcx.tcx.erase_regions(&normalized_value) + let normalized_value = infcx.resolve_vars_if_possible(normalized_value); + infcx.tcx.erase_regions(normalized_value) } Err(NoSolution) => bug!("could not fully normalize `{:?}`", value), } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 139ed6dcd35..0addde5c44c 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -70,7 +70,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { DUMMY_SP, hir::CRATE_HIR_ID, self.param_env, - &value, + value, ) .into_value_registering_obligations(self.infcx, self.fulfill_cx) } @@ -184,7 +184,7 @@ where { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = - infcx.at(&ObligationCause::dummy(), param_env).normalize(&value)?; + infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?; fulfill_cx.register_predicate_obligations(infcx, obligations); Ok(value) } diff --git a/compiler/rustc_ty/src/instance.rs b/compiler/rustc_ty/src/instance.rs index 220f4cec742..cf2c6efb471 100644 --- a/compiler/rustc_ty/src/instance.rs +++ b/compiler/rustc_ty/src/instance.rs @@ -51,7 +51,7 @@ fn inner_resolve_instance<'tcx>( resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def.def_id_for_type_of()); - let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); + let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty); let def = match *item_type.kind() { ty::FnDef(..) @@ -146,7 +146,7 @@ fn resolve_associated_item<'tcx>( substs, leaf_def.defining_node, ); - infcx.tcx.erase_regions(&substs) + infcx.tcx.erase_regions(substs) }); // Since this is a trait item, we need to see if the item is either a trait default item @@ -172,7 +172,7 @@ fn resolve_associated_item<'tcx>( return Ok(None); } - let substs = tcx.erase_regions(&substs); + let substs = tcx.erase_regions(substs); // Check if we just resolved an associated `const` declaration from // a `trait` to an associated `const` definition in an `impl`, where @@ -192,7 +192,7 @@ fn resolve_associated_item<'tcx>( && leaf_def.item.def_id.is_local() { let normalized_type_of = |def_id, substs| { - tcx.subst_and_normalize_erasing_regions(substs, param_env, &tcx.type_of(def_id)) + tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id)) }; let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs); @@ -264,7 +264,7 @@ fn resolve_associated_item<'tcx>( assert_eq!(name, sym::clone_from); // Use the default `fn clone_from` from `trait Clone`. - let substs = tcx.erase_regions(&rcvr_substs); + let substs = tcx.erase_regions(rcvr_substs); Some(ty::Instance::new(def_id, substs)) } } else { diff --git a/compiler/rustc_ty/src/needs_drop.rs b/compiler/rustc_ty/src/needs_drop.rs index 0356bcec549..d62fc764c76 100644 --- a/compiler/rustc_ty/src/needs_drop.rs +++ b/compiler/rustc_ty/src/needs_drop.rs @@ -107,7 +107,7 @@ where let witness = substs.witness(); let interior_tys = match witness.kind() { - ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), + &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), _ => { tcx.sess.delay_span_bug( tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs index 2562140bb5d..720ad42da2a 100644 --- a/compiler/rustc_ty/src/ty.rs +++ b/compiler/rustc_ty/src/ty.rs @@ -363,7 +363,7 @@ fn well_formed_types_in_env<'tcx>( // well-formed. NodeKind::Fn => { let fn_sig = tcx.fn_sig(def_id); - let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); + let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 3bfb2d3f1b0..0db5fda272a 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -1,12 +1,13 @@ use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, + AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + GenericArgCountResult, GenericArgPosition, }; use crate::errors::AssocTypeBindingNotAllowed; use rustc_ast::ast::ParamKindOrd; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{GenericArg, GenericArgs}; +use rustc_hir::GenericArg; use rustc_middle::ty::{ self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, }; @@ -22,6 +23,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { sess: &Session, arg: &GenericArg<'_>, kind: &'static str, + possible_ordering_error: bool, help: Option<&str>, ) { let mut err = struct_span_err!( @@ -48,8 +50,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericArg::Const(_) => ParamKindOrd::Const { unordered }, }; + if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })) + && matches!(kind_ord, ParamKindOrd::Const { .. }) + { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + err.multipart_suggestion( + "if this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } + // This note is only true when generic parameters are strictly ordered by their kind. - if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { + if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { let (first, last) = if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; err.note(&format!("{} arguments must be provided before {} arguments", first, last)); @@ -90,20 +107,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// instantiate a `GenericArg`. /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then /// creates a suitable inference variable. - pub fn create_substs_for_generic_args<'b>( + pub fn create_substs_for_generic_args<'a>( tcx: TyCtxt<'tcx>, def_id: DefId, parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option<Ty<'tcx>>, arg_count: GenericArgCountResult, - args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), - mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, - mut inferred_kind: impl FnMut( - Option<&[subst::GenericArg<'tcx>]>, - &GenericParamDef, - bool, - ) -> subst::GenericArg<'tcx>, + ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, ) -> SubstsRef<'tcx> { // Collect the segments of the path; we need to substitute arguments // for parameters throughout the entire path (wherever there are @@ -142,7 +153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { substs.push( self_ty .map(|ty| ty.into()) - .unwrap_or_else(|| inferred_kind(None, param, true)), + .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), ); params.next(); } @@ -151,10 +162,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_args) = args_for_def_id(def_id); + let (generic_args, infer_args) = ctx.args_for_def_id(def_id); - let mut args = - generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); + let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); + let mut args = args_iter.clone().peekable(); // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. // If we later encounter a lifetime, we know that the arguments were provided in the @@ -173,7 +184,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { - substs.push(provided_kind(param, arg)); + substs.push(ctx.provided_kind(param, arg)); args.next(); params.next(); } @@ -184,7 +195,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - substs.push(inferred_kind(None, param, infer_args)); + substs.push(ctx.inferred_kind(None, param, infer_args)); force_infer_lt = Some(arg); params.next(); } @@ -221,8 +232,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Const => { ParamKindOrd::Const { unordered: tcx - .sess - .features_untracked() + .features() .const_generics, } } @@ -242,6 +252,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.sess, arg, kind.descr(), + !args_iter.clone().is_sorted_by_key(|arg| match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const { + unordered: tcx.features().const_generics, + }, + }), Some(&format!( "reorder the arguments: {}: `<{}>`", param_types_present @@ -293,7 +310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(kind, "lifetime"); let provided = force_infer_lt.expect("lifetimes ought to have been inferred"); - Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None); } break; @@ -302,7 +319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - substs.push(inferred_kind(Some(&substs), param, infer_args)); + substs.push(ctx.inferred_kind(Some(&substs), param, infer_args)); params.next(); } @@ -351,6 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // that lifetimes will proceed types. So it suffices to check the number of each generic // arguments in order to validate them with respect to the generic parameters. let param_counts = def.own_counts(); + let named_type_param_count = param_counts.types - has_self as usize; let arg_counts = args.own_counts(); let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; @@ -389,11 +407,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // For kinds without defaults (e.g.., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { - return Ok(()); + return true; } if silent { - return Err((0i32, None)); + return false; } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -409,25 +427,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (required, "") }; - let (spans, label) = if required == permitted && provided > permitted { + let (spans, labels) = if provided > permitted { // In the case when the user has provided too many arguments, // we want to point to the unexpected arguments. - let spans: Vec<Span> = args.args[offset + permitted..offset + provided] + let (spans, labels): (Vec<Span>, Vec<String>) = args.args + [offset + permitted..offset + provided] .iter() - .map(|arg| arg.span()) - .collect(); + .map(|arg| (arg.span(), format!("unexpected {} argument", arg.short_descr()))) + .unzip(); unexpected_spans.extend(spans.clone()); - (spans, format!("unexpected {} argument", kind)) + (spans, labels) } else { ( vec![span], - format!( + vec![format!( "expected {}{} {} argument{}", quantifier, bound, kind, pluralize!(bound), - ), + )], ) }; @@ -439,105 +458,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ), DiagnosticId::Error("E0107".into()), ); - for span in spans { + for (span, label) in spans.into_iter().zip(labels) { err.span_label(span, label.as_str()); } - - assert_ne!(bound, provided); - Err((bound as i32 - provided as i32, Some(err))) + err.emit(); + false }; let mut unexpected_spans = vec![]; - let mut lifetime_count_correct = Ok(()); - if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - lifetime_count_correct = check_kind_count( - "lifetime", - param_counts.lifetimes, - param_counts.lifetimes, - arg_counts.lifetimes, - 0, - &mut unexpected_spans, - explicit_late_bound == ExplicitLateBound::Yes, - ); - } - - // FIXME(const_generics:defaults) - let mut const_count_correct = Ok(()); - if !infer_args || arg_counts.consts > param_counts.consts { - const_count_correct = check_kind_count( - "const", - param_counts.consts, - param_counts.consts, - arg_counts.consts, - arg_counts.lifetimes + arg_counts.types, - &mut unexpected_spans, - false, - ); - } - - // Note that type errors are currently be emitted *after* const errors. - let mut type_count_correct = Ok(()); - if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize - { - type_count_correct = check_kind_count( - "type", - param_counts.types - defaults.types - has_self as usize, - param_counts.types - has_self as usize, - arg_counts.types, - arg_counts.lifetimes, - &mut unexpected_spans, - false, - ); - } - - // Emit a help message if it's possible that a type could be surrounded in braces - if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { - if let Err((_, Some(ref mut type_err))) = type_count_correct { - let possible_matches = args.args[arg_counts.lifetimes..] - .iter() - .filter(|arg| { - matches!( - arg, - GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }) - ) - }) - .take(c_mismatch.max(0) as usize); - for arg in possible_matches { - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - type_err.multipart_suggestion( - "If this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } + let lifetime_count_correct = check_kind_count( + "lifetime", + if infer_lifetimes { 0 } else { param_counts.lifetimes }, + param_counts.lifetimes, + arg_counts.lifetimes, + 0, + &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, + ); - let emit_correct = - |correct: Result<(), (_, Option<rustc_errors::DiagnosticBuilder<'_>>)>| match correct { - Ok(()) => Ok(()), - Err((_, None)) => Err(()), - Err((_, Some(mut err))) => { - err.emit(); - Err(()) - } - }; + let kind_str = if param_counts.consts + arg_counts.consts == 0 { + "type" + } else if named_type_param_count + arg_counts.types == 0 { + "const" + } else { + "generic" + }; - let arg_count_correct = emit_correct(lifetime_count_correct) - .and(emit_correct(const_count_correct)) - .and(emit_correct(type_count_correct)); + let arg_count_correct = check_kind_count( + kind_str, + if infer_args { + 0 + } else { + param_counts.consts + named_type_param_count - defaults.types + }, + param_counts.consts + named_type_param_count, + arg_counts.consts + arg_counts.types, + arg_counts.lifetimes, + &mut unexpected_spans, + false, + ); GenericArgCountResult { explicit_late_bound, - correct: arg_count_correct.map_err(|()| GenericArgCountMismatch { - reported: Some(ErrorReported), - invalid_args: unexpected_spans, - }), + correct: if lifetime_count_correct && arg_count_correct { + Ok(()) + } else { + Err(GenericArgCountMismatch { + reported: Some(ErrorReported), + invalid_args: unexpected_spans, + }) + }, } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 07e523af3eb..89c5adfa14c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -165,6 +165,23 @@ pub struct GenericArgCountResult { pub correct: Result<(), GenericArgCountMismatch>, } +pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { + fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool); + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx>; + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx>; +} + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -321,81 +338,102 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - 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 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; + + struct SubstsForAstPathCtxt<'a, 'tcx> { + astconv: &'a (dyn AstConv<'tcx> + 'a), + def_id: DefId, + generic_args: &'a GenericArgs<'a>, + span: Span, + missing_type_params: Vec<String>, + inferred_params: Vec<Span>, + infer_args: bool, + is_object: bool, + } + + impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { + fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { + let tcx = self.astconv.tcx(); + if let GenericParamDefKind::Type { has_default, .. } = param.kind { + if self.is_object && has_default { + let default_ty = tcx.at(self.span).type_of(param.def_id); + let self_param = tcx.types.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; + } } } - } - false - }; + false + } + } - let mut missing_type_params = vec![]; - let mut inferred_params = vec![]; - let substs = Self::create_substs_for_generic_args( - tcx, - def_id, - parent_substs, - self_ty.is_some(), - self_ty, - arg_count.clone(), - // Provide the generic args, and whether types should be inferred. - |did| { - if did == def_id { - (Some(generic_args), infer_args) + impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { + fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { + if did == self.def_id { + (Some(self.generic_args), self.infer_args) } else { // The last component of this tuple is unimportant. (None, false) } - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.ast_region_to_region(<, Some(param)).into() - } - (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { - if *has_default { - tcx.check_optional_stability( - param.def_id, - Some(arg.id()), - arg.span(), - |_, _| { - // Default generic parameters may not be marked - // with stability attributes, i.e. when the - // default parameter was defined at the same time - // as the rest of the type. As such, we ignore missing - // stability attributes. + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + self.astconv.ast_region_to_region(<, Some(param)).into() + } + (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ) + } + if let (hir::TyKind::Infer, false) = + (&ty.kind, self.astconv.allow_ty_infer()) + { + self.inferred_params.push(ty.span); + tcx.ty_error().into() + } else { + self.astconv.ast_ty_to_ty(&ty).into() + } + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + ty::Const::from_opt_const_arg_anon_const( + tcx, + ty::WithOptConstParam { + did: tcx.hir().local_def_id(ct.value.hir_id), + const_param_did: Some(param.def_id), }, ) + .into() } - if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { - inferred_params.push(ty.span); - tcx.ty_error().into() - } else { - self.ast_ty_to_ty(&ty).into() - } - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - ty::Const::from_opt_const_arg_anon_const( - tcx, - ty::WithOptConstParam { - did: tcx.hir().local_def_id(ct.value.hir_id), - const_param_did: Some(param.def_id), - }, - ) - .into() + _ => unreachable!(), } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { + } + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), GenericParamDefKind::Type { has_default, .. } => { @@ -407,48 +445,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // other type parameters may reference `Self` in their // defaults. This will lead to an ICE if we are not // careful! - if default_needs_object_self(param) { - missing_type_params.push(param.name.to_string()); + if self.default_needs_object_self(param) { + self.missing_type_params.push(param.name.to_string()); tcx.ty_error().into() } else { // This is a default type parameter. - self.normalize_ty( - span, - tcx.at(span).type_of(param.def_id).subst_spanned( - tcx, - substs.unwrap(), - Some(span), - ), - ) - .into() + self.astconv + .normalize_ty( + self.span, + tcx.at(self.span).type_of(param.def_id).subst_spanned( + tcx, + substs.unwrap(), + Some(self.span), + ), + ) + .into() } } else if infer_args { // No type parameters were provided, we can infer all. - let param = - if !default_needs_object_self(param) { Some(param) } else { None }; - self.ty_infer(param, span).into() + let param = if !self.default_needs_object_self(param) { + Some(param) + } else { + None + }; + self.astconv.ty_infer(param, self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() } } GenericParamDefKind::Const => { - let ty = tcx.at(span).type_of(param.def_id); + let ty = tcx.at(self.span).type_of(param.def_id); // FIXME(const_generics:defaults) if infer_args { // No const parameters were provided, we can infer all. - self.ct_infer(ty, Some(param), span).into() + self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.const_error(ty).into() } } } - }, + } + } + + let mut substs_ctx = SubstsForAstPathCtxt { + astconv: self, + def_id, + span, + generic_args, + missing_type_params: vec![], + inferred_params: vec![], + infer_args, + is_object, + }; + let substs = Self::create_substs_for_generic_args( + tcx, + def_id, + parent_substs, + self_ty.is_some(), + self_ty, + arg_count.clone(), + &mut substs_ctx, ); self.complain_about_missing_type_params( - missing_type_params, + substs_ctx.missing_type_params, def_id, span, generic_args.args.is_empty(), diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index e8eea65137f..3a5eeb5381b 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { id, self.body_id, self.param_env, - &ty, + ty, arm.body.span, ); let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index a38fb9642b9..ebfb401fcf3 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( call_expr.span, infer::FnCall, - &closure_sig, + closure_sig, ) .0; let adjustments = self.adjust_steps(autoderef); @@ -407,8 +407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // previously appeared within a `Binder<>` and hence would not // have been normalized before. let fn_sig = - self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig).0; - let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); + self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig).0; + let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig); // Call the generic checker. let expected_arg_tys = self.expected_inputs_for_expected_output( diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 5c2bdb86f76..36240a9b41e 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Result<Option<PointerKind<'tcx>>, ErrorReported> { debug!("pointer_kind({:?}, {:?})", t, span); - let t = self.resolve_vars_if_possible(&t); + let t = self.resolve_vars_if_possible(t); if t.references_error() { return Err(ErrorReported); @@ -377,12 +377,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion: if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { - let ty = fcx.resolve_vars_if_possible(&self.cast_ty); + let ty = fcx.resolve_vars_if_possible(self.cast_ty); // Erase regions to avoid panic in `prove_value` when calling // `type_implements_trait`. - let ty = fcx.tcx.erase_regions(&ty); - let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty); - let expr_ty = fcx.tcx.erase_regions(&expr_ty); + let ty = fcx.tcx.erase_regions(ty); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let expr_ty = fcx.tcx.erase_regions(expr_ty); let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); // Check for infer types because cases like `Option<{integer}>` would // panic otherwise. @@ -471,7 +471,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, E0620, "cast to unsized type: `{}` as `{}`", - fcx.resolve_vars_if_possible(&self.expr_ty), + fcx.resolve_vars_if_possible(self.expr_ty), tstr ); match self.expr_ty.kind() { @@ -607,7 +607,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Attempt a coercion to a fn pointer type. let f = fcx.normalize_associated_types_in( self.expr.span, - &self.expr_ty.fn_sig(fcx.tcx), + self.expr_ty.fn_sig(fcx.tcx), ); let res = fcx.try_coerce( self.expr, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 70d94ef869d..1220c313932 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -75,7 +75,7 @@ pub(super) fn check_fn<'a, 'tcx>( let declared_ret_ty = fn_sig.output(); let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); + fcx.instantiate_opaque_types_from_value(fn_id, declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fcx.ret_type_span = Some(decl.output.span()); @@ -446,24 +446,24 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( struct ProhibitOpaqueVisitor<'tcx> { opaque_identity_ty: Ty<'tcx>, generics: &'tcx ty::Generics, - ty: Option<Ty<'tcx>>, }; impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = Option<Ty<'tcx>>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { - self.ty = Some(t); - return ControlFlow::BREAK; + return ControlFlow::Break(Some(t)); } ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { if *index < self.generics.parent_count as u32 { - return ControlFlow::BREAK; + return ControlFlow::Break(None); } else { return ControlFlow::CONTINUE; } @@ -472,7 +472,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ConstKind::Unevaluated(..) = c.val { // FIXME(#72219) We currenctly don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used @@ -494,18 +494,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), ), generics: tcx.generics_of(def_id), - ty: None, }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor).is_break()); + .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); debug!( "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", prohibit_opaque, visitor ); - if prohibit_opaque { + if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { hir::OpaqueTyOrigin::AsyncFn => true, @@ -525,7 +524,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { if snippet == "Self" { - if let Some(ty) = visitor.ty { + if let Some(ty) = ty { err.span_suggestion( span, "consider spelling out the type instead", @@ -601,7 +600,7 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); let (_, opaque_type_map) = inh.register_infer_ok_obligations( - infcx.instantiate_opaque_types(def_id, hir_id, param_env, &opaque_ty, span), + infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span), ); for (def_id, opaque_defn) in opaque_type_map { @@ -1455,7 +1454,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { { struct VisitTypes(Vec<DefId>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match *t.kind() { ty::Opaque(def, _) => { self.0.push(def); diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 2ba05071c05..8082a230216 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -257,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let input_tys = if is_fn { let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); - let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty); + let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); match arg_param_ty.kind() { @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ret_param_ty = projection.skip_binder().ty; - let ret_param_ty = self.resolve_vars_if_possible(&ret_param_ty); + let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); let sig = self.tcx.mk_fn_sig( @@ -400,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `deduce_expectations_from_expected_type` introduces // late-bound lifetimes defined elsewhere, which we now // anonymize away, so as not to confuse the user. - let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig); + let bound_sig = self.tcx.anonymize_late_bound_regions(bound_sig); let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig); @@ -500,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( hir_ty.span, LateBoundRegionConversionTime::FnCall, - &ty::Binder::bind(supplied_ty), + ty::Binder::bind(supplied_ty), ); // recreated from (*) above // Check that E' = S'. @@ -513,7 +513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( decl.output.span(), LateBoundRegionConversionTime::FnCall, - &supplied_sig.output(), + supplied_sig.output(), ); let cause = &self.misc(decl.output.span()); let InferOk { value: (), obligations } = self @@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("supplied_sig_of_closure: result={:?}", result); - let c_result = self.inh.infcx.canonicalize_response(&result); + let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); result @@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the type from the projection. Note that there can // be no bound variables in this type because the "self type" // does not have any regions in it. - let output_ty = self.resolve_vars_if_possible(&predicate.ty); + let output_ty = self.resolve_vars_if_possible(predicate.ty); debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty); Some(output_ty) } @@ -723,12 +723,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, bound_sig: ty::PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, &bound_sig); + let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, bound_sig); let liberated_sig = self.inh.normalize_associated_types_in( body.value.span, body.value.hir_id, self.param_env, - &liberated_sig, + liberated_sig, ); ClosureSignatures { bound_sig, liberated_sig } } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 6da3ecde329..0f5f0ab0260 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -606,7 +606,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Uncertain or unimplemented. Ok(None) => { if trait_pred.def_id() == unsize_did { - let trait_pred = self.resolve_vars_if_possible(&trait_pred); + 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); @@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let InferOk { value: a_sig, mut obligations } = - self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); + self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig); let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( @@ -973,8 +973,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { // The signature must match. - let a_sig = self.normalize_associated_types_in(new.span, &a_sig); - let b_sig = self.normalize_associated_types_in(new.span, &b_sig); + let a_sig = self.normalize_associated_types_in(new.span, a_sig); + let b_sig = self.normalize_associated_types_in(new.span, b_sig); let sig = self .at(cause, self.param_env) .trace(prev_ty, new_ty) @@ -1490,7 +1490,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { *sp, &format!( "return type inferred to be `{}` here", - fcx.resolve_vars_if_possible(&expected) + fcx.resolve_vars_if_possible(expected) ), ); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 4acc7451a21..20090d37606 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -224,11 +224,11 @@ fn compare_predicate_entailment<'tcx>( let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - &ty::Binder::bind(impl_m_own_bounds.predicates), + ty::Binder::bind(impl_m_own_bounds.predicates), ); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); inh.register_predicates(obligations); inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); @@ -253,17 +253,17 @@ fn compare_predicate_entailment<'tcx>( let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - &tcx.fn_sig(impl_m.def_id), + tcx.fn_sig(impl_m.def_id), ); let impl_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &impl_sig); + inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); - let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id)); + let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); let trait_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig); + inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -499,7 +499,7 @@ fn compare_self_type<'tcx>( tcx.infer_ctxt().enter(|infcx| { let self_arg_ty = - tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_arg_ty)); + tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_arg_ty)); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { ExplicitSelf::ByValue => "self".to_owned(), @@ -968,12 +968,12 @@ crate fn compare_const_impl<'tcx>( // There is no "body" here, so just pass dummy id. let impl_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &impl_ty); + inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); let trait_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &trait_ty); + inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty); debug!("compare_const_impl: trait_ty={:?}", trait_ty); @@ -1136,7 +1136,7 @@ fn compare_type_predicate_entailment<'tcx>( for predicate in impl_ty_own_bounds.predicates { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); inh.register_predicates(obligations); inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); @@ -1261,7 +1261,7 @@ pub fn check_type_bounds<'tcx>( &mut selcx, normalize_param_env, normalize_cause.clone(), - &obligation.predicate, + obligation.predicate, ); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 5650b2cdd3c..ad675f1e383 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -366,8 +366,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { // Anonymizing the LBRs is necessary to solve (Issue #59497). // After we do so, it should be totally fine to skip the binders. - let anon_a = self.tcx.anonymize_late_bound_regions(&a); - let anon_b = self.tcx.anonymize_late_bound_regions(&b); + let anon_a = self.tcx.anonymize_late_bound_regions(a); + let anon_b = self.tcx.anonymize_late_bound_regions(b); self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; Ok(a) diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs index fd6fe1406c8..5a5fc893d65 100644 --- a/compiler/rustc_typeck/src/check/expectation.rs +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -83,9 +83,9 @@ impl<'a, 'tcx> Expectation<'tcx> { fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match self { NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), + ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)), + ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)), + ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)), } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index af19ad08c1d..f7f9e607a74 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( expr.span, infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.input(i), + fn_sig.input(i), ) .0; self.require_type_is_sized_deferred( @@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( expr.span, infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.output(), + fn_sig.output(), ) .0; self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); @@ -963,9 +963,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_cast = self.to_ty_saving_user_provided_ty(t); - let t_cast = self.resolve_vars_if_possible(&t_cast); + let t_cast = self.resolve_vars_if_possible(t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); - let t_cast = self.resolve_vars_if_possible(&t_cast); + let t_cast = self.resolve_vars_if_possible(t_cast); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|f| { self.normalize_associated_types_in( expr.span, - &f.ty(self.tcx, substs), + f.ty(self.tcx, substs), ) }) .collect(); @@ -1571,7 +1571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { let output_ty = match self.infcx.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; let mut add_label = true; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 0bb7b464f16..e1a2f593b8d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1,5 +1,6 @@ use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, + AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + GenericArgCountResult, PathSeg, }; use crate::check::callee::{self, DeferredCallResolution}; use crate::check::method::{self, MethodCallee, SelfSource}; @@ -87,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(ty); if !ty.has_infer_types_or_consts() { debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; @@ -98,7 +99,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(false, |_| {}); - ty = self.resolve_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(ty); debug!("resolve_vars_with_obligations: ty={:?}", ty); ty @@ -133,12 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[inline] pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { - debug!( - "write_ty({:?}, {:?}) in fcx {}", - id, - self.resolve_vars_if_possible(&ty), - self.tag() - ); + debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); if ty.references_error() { @@ -194,7 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { user_self_ty: None, // not relevant here }; - self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( method.def_id, user_substs, )) @@ -239,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); @@ -325,13 +321,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Basically whenever we are converting from a type scheme into /// the fn body space, we always want to normalize associated /// types as well. This function combines the two. - fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T + fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { + debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs); let value = value.subst(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); + let result = self.normalize_associated_types_in(span, value); + debug!("instantiate_type_scheme = {:?}", result); result } @@ -346,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bounds = self.tcx.predicates_of(def_id); let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect(); let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result); + let result = self.normalize_associated_types_in(span, result); debug!( "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", bounds, substs, result, spans, @@ -360,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( &self, parent_id: hir::HirId, - value: &T, + value: T, value_span: Span, ) -> T { let parent_def_id = self.tcx.hir().local_def_id(parent_id); @@ -388,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value } - pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T + pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -398,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>( &self, span: Span, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>, @@ -467,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); + let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } @@ -850,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Record all the argument types, with the substitutions // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) + Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()) }) .unwrap_or_default(); debug!( @@ -1203,7 +1200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Res::Local(hid) = res { let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); + let ty = self.normalize_associated_types_in(span, ty); self.write_ty(hir_id, ty); return (ty, res); } @@ -1298,76 +1295,108 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; - let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( - tcx, - def_id, - &[][..], - has_self, - self_ty, - arg_count, - // Provide the generic args, and whether types should be inferred. - |def_id| { - if let Some(&PathSeg(_, index)) = - path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) - { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !infer_args_for_err.contains(&index) { - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_args); - } + struct CreateCtorSubstsContext<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, + path_segs: &'a [PathSeg], + infer_args_for_err: &'a FxHashSet<usize>, + segments: &'a [hir::PathSegment<'a>], + } + impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> { + fn args_for_def_id( + &mut self, + def_id: DefId, + ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + if let Some(&PathSeg(_, index)) = + self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) + { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !self.infer_args_for_err.contains(&index) { + // Check whether the user has provided generic arguments. + if let Some(ref data) = self.segments[index].args { + return (Some(data), self.segments[index].infer_args); } - return (None, segments[index].infer_args); } + return (None, self.segments[index].infer_args); + } - (None, true) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { + (None, true) + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() + AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.to_ty(ty).into() + self.fcx.to_ty(ty).into() } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() + self.fcx.const_arg_to_const(&ct.value, param.def_id).into() } _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => { - self.re_infer(Some(param), span).unwrap().into() - } - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then we it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - let default = tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(tcx, substs.unwrap(), Some(span)), + } + } + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx> { + let tcx = self.fcx.tcx(); + match param.kind { + GenericParamDefKind::Lifetime => { + self.fcx.re_infer(Some(param), self.span).unwrap().into() + } + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. + let default = tcx.type_of(param.def_id); + self.fcx + .normalize_ty( + self.span, + default.subst_spanned(tcx, substs.unwrap(), Some(self.span)), ) .into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.var_for_def(span, param) - } - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - // No const parameters were provided, we have to infer them. - self.var_for_def(span, param) + } else { + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type parameter. + // Using inference instead of `Error` gives better error messages. + self.fcx.var_for_def(self.span, param) } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.fcx.var_for_def(self.span, param) + } + } + } + } + + let substs = self_ctor_substs.unwrap_or_else(|| { + AstConv::create_substs_for_generic_args( + tcx, + def_id, + &[][..], + has_self, + self_ty, + arg_count, + &mut CreateCtorSubstsContext { + fcx: self, + span, + path_segs: &path_segs, + infer_args_for_err: &infer_args_for_err, + segments, }, ) }); @@ -1381,7 +1410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); + let ty_substituted = self.instantiate_type_scheme(span, &substs, ty); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method` @@ -1391,7 +1420,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. let ty = tcx.type_of(impl_def_id); - let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + let impl_ty = self.instantiate_type_scheme(span, &substs, ty); match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a820661d843..333bda00dbe 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -261,9 +261,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // is the missing argument of type `()`? let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() + self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit() } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() + self.resolve_vars_if_possible(fn_inputs[0]).is_unit() } else { false }; @@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::FnDef(..) => { let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); + let ptr_ty = self.resolve_vars_if_possible(ptr_ty); variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); } _ => {} @@ -927,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .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`. if ty.walk().any(|arg| arg == predicate.self_ty().into()) { @@ -989,7 +989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // from `typeck-default-trait-impl-assoc-type.rs`. } else { let ty = AstConv::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if ty == predicate.self_ty() { error.obligation.cause.make_mut().span = hir_ty.span; } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 72c3b233ed9..f635e0b6f93 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( span, infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, + poly_trait_ref, ); let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index a8ad9f4fdf8..17dbf989d66 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -73,8 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; - let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; - let sig = self.normalize_associated_types_in(expr.span, &sig); + let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig).0; + let sig = self.normalize_associated_types_in(expr.span, sig); if self.can_coerce(sig.output(), expected) { let (mut sugg_call, applicability) = if sig.inputs().is_empty() { (String::new(), Applicability::MachineApplicable) diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index af552389de0..825ebc19fa6 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -59,16 +59,13 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let o_ty = self.fcx.to_ty(&ty); let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) + self.fcx.instantiate_opaque_types_from_value(self.parent_id, o_ty, ty.span) } else { o_ty }; - let c_ty = self - .fcx - .inh - .infcx - .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); + let c_ty = + self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(revealed_ty)); debug!( "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", ty.hir_id, o_ty, revealed_ty, c_ty diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 293a995887c..602b79802b3 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }); if let Some(yield_data) = live_across_yield { - let ty = self.fcx.resolve_vars_if_possible(&ty); + let ty = self.fcx.resolve_vars_if_possible(ty); debug!( "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", expr, scope, ty, self.expr_count, yield_data.span @@ -120,7 +120,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.expr_count, expr.map(|e| e.span) ); - let ty = self.fcx.resolve_vars_if_possible(&ty); + let ty = self.fcx.resolve_vars_if_possible(ty); if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { @@ -179,13 +179,13 @@ pub fn resolve_interior<'a, 'tcx>( .filter_map(|mut cause| { // Erase regions and canonicalize late-bound regions to deduplicate as many types as we // can. - let erased = fcx.tcx.erase_regions(&cause.ty); + let erased = fcx.tcx.erase_regions(cause.ty); if captured_tys.insert(erased) { // Replace all regions inside the generator interior with late bound regions. // Note that each region slot in the types gets a new fresh late bound region, // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. - let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| { + let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))); counter += 1; r diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 7e580485c3d..0011a3fc71b 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -156,7 +156,7 @@ impl Inherited<'a, 'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index fd2700b85e2..8ef723d5902 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -1,6 +1,6 @@ use super::{probe, MethodCallee}; -use crate::astconv::AstConv; +use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt}; use crate::check::{callee, FnCtxt}; use crate::hir::def_id::DefId; use crate::hir::GenericArg; @@ -10,7 +10,7 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::subst::{self, Subst, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty}; use rustc_span::Span; use rustc_trait_selection::traits; @@ -90,8 +90,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // traits, no trait system method can be called before this point because they // could alter our Self-type, except for normalizing the receiver from the // signature (which is also done during probing). - let method_sig_rcvr = - self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]); + let method_sig_rcvr = self.normalize_associated_types_in(self.span, method_sig.inputs()[0]); debug!( "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", self_ty, method_sig_rcvr, method_sig, method_predicates @@ -99,7 +98,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs); let (method_sig, method_predicates) = - self.normalize_associated_types_in(self.span, &(method_sig, method_predicates)); + self.normalize_associated_types_in(self.span, (method_sig, method_predicates)); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); @@ -229,7 +228,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = - this.replace_bound_vars_with_fresh_vars(&upcast_poly_trait_ref); + this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref); debug!( "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", original_poly_trait_ref, upcast_trait_ref, trait_def_id @@ -249,10 +248,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.fresh_substs_for_item(self.span, trait_def_id) } - probe::WhereClausePick(ref poly_trait_ref) => { + probe::WhereClausePick(poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - self.replace_bound_vars_with_fresh_vars(&poly_trait_ref).substs + self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs } } } @@ -307,6 +306,52 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // parameters from the type and those from the method. assert_eq!(generics.parent_count, parent_substs.len()); + struct MethodSubstsCtxt<'a, 'tcx> { + cfcx: &'a ConfirmContext<'a, 'tcx>, + pick: &'a probe::Pick<'tcx>, + seg: &'a hir::PathSegment<'a>, + } + impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> { + fn args_for_def_id( + &mut self, + def_id: DefId, + ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + if def_id == self.pick.item.def_id { + if let Some(ref data) = self.seg.args { + return (Some(data), false); + } + } + (None, false) + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.cfcx.to_ty(ty).into() + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.cfcx.const_arg_to_const(&ct.value, param.def_id).into() + } + _ => unreachable!(), + } + } + + fn inferred_kind( + &mut self, + _substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + _infer_args: bool, + ) -> subst::GenericArg<'tcx> { + self.cfcx.var_for_def(self.cfcx.span, param) + } + } AstConv::create_substs_for_generic_args( self.tcx, pick.item.def_id, @@ -314,29 +359,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { false, None, arg_count_correct, - // Provide the generic args, and whether types should be inferred. - |def_id| { - // The last component of the returned tuple here is unimportant. - if def_id == pick.item.def_id { - if let Some(ref data) = seg.args { - return (Some(data), false); - } - } - (None, false) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(), - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |_, param, _| self.var_for_def(self.span, param), + &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ) } @@ -400,7 +423,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // N.B., instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_bound_vars_with_fresh_vars(&sig); + let method_sig = self.replace_bound_vars_with_fresh_vars(sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = method_sig.subst(self.tcx, all_substs); @@ -506,7 +529,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { upcast_trait_refs.into_iter().next().unwrap() } - fn replace_bound_vars_with_fresh_vars<T>(&self, value: &ty::Binder<T>) -> T + fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<T>) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 84bc3979e12..8e13b374699 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope: ProbeScope, ) -> probe::PickResult<'tcx> { let mode = probe::Mode::MethodCall; - let self_ty = self.resolve_vars_if_possible(&self_ty); + let self_ty = self.resolve_vars_if_possible(self_ty); self.probe_for_name( span, mode, @@ -358,11 +358,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `instantiate_type_scheme` can normalize associated types that // may reference those regions. let fn_sig = tcx.fn_sig(def_id); - let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, &fn_sig).0; + let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0; let fn_sig = fn_sig.subst(self.tcx, substs); let InferOk { value, obligations: o } = - self.normalize_associated_types_in_as_infer_ok(span, &fn_sig); + self.normalize_associated_types_in_as_infer_ok(span, fn_sig); let fn_sig = { obligations.extend(o); value @@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); let InferOk { value, obligations: o } = - self.normalize_associated_types_in_as_infer_ok(span, &bounds); + self.normalize_associated_types_in_as_infer_ok(span, bounds); let bounds = { obligations.extend(o); value diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 713b24e583a..478f8a16169 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -25,7 +25,6 @@ use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_session::config::nightly_options; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; @@ -309,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut orig_values = OriginalQueryValues::default(); let param_env_and_self_ty = self.infcx.canonicalize_query( - &ParamEnvAnd { param_env: self.param_env, value: self_ty }, + ParamEnvAnd { param_env: self.param_env, value: self_ty }, &mut orig_values, ); @@ -731,7 +730,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); let selcx = &mut traits::SelectionContext::new(self.fcx); let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } = - traits::normalize(selcx, self.param_env, cause, &xform_tys); + traits::normalize(selcx, self.param_env, cause, xform_tys); debug!( "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}", xform_self_ty, xform_ret_ty @@ -775,7 +774,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // argument type like `&Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { - let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -821,7 +820,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { - let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); + let trait_ref = this.erase_late_bound_regions(poly_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); @@ -912,7 +911,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let substs = self.fresh_substs_for_item(self.span, method.def_id); let fty = fty.subst(self.tcx, substs); let (fty, _) = - self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, &fty); + self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); if let Some(self_ty) = self_ty { if self @@ -943,7 +942,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // For trait aliases, assume all super-traits are relevant. let bounds = iter::once(trait_ref.to_poly_trait_ref()); self.elaborate_bounds(bounds, |this, new_trait_ref, item| { - let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -1272,7 +1271,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.tcx.def_path_str(stable_pick.item.def_id), )); - if nightly_options::is_nightly_build() { + if self.tcx.sess.is_nightly_build() { for (candidate, feature) in unstable_candidates { diag.help(&format!( "add `#![feature({})]` to the crate attributes to enable `{}`", @@ -1356,7 +1355,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let impl_bounds = self.tcx.predicates_of(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = - traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds); + traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds); // Convert the bounds into obligations. let impl_obligations = @@ -1367,7 +1366,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .chain(ref_obligations.iter().cloned()); // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { - let o = self.resolve_vars_if_possible(&o); + let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; possibly_unsatisfied_predicates.push((o.predicate, None)); @@ -1393,25 +1392,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { for obligation in impl_source.borrow_nested_obligations() { // Determine exactly which obligation wasn't met, so // that we can give more context in the error. - if !self.predicate_may_hold(&obligation) { - let o = self.resolve_vars_if_possible(obligation); + if !self.predicate_may_hold(obligation) { + let nested_predicate = + self.resolve_vars_if_possible(obligation.predicate); let predicate = - self.resolve_vars_if_possible(&predicate); - let p = if predicate == o.predicate { + self.resolve_vars_if_possible(predicate); + let p = if predicate == nested_predicate { // Avoid "`MyStruct: Foo` which is required by // `MyStruct: Foo`" in E0599. None } else { Some(predicate) }; - possibly_unsatisfied_predicates.push((o.predicate, p)); + possibly_unsatisfied_predicates + .push((nested_predicate, p)); } } } _ => { // Some nested subobligation of this predicate // failed. - let predicate = self.resolve_vars_if_possible(&predicate); + let predicate = self.resolve_vars_if_possible(predicate); possibly_unsatisfied_predicates.push((predicate, None)); } } @@ -1428,7 +1429,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for o in sub_obligations { - let o = self.resolve_vars_if_possible(&o); + let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; possibly_unsatisfied_predicates.push((o.predicate, None)); @@ -1439,7 +1440,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, probe.xform_ret_ty) { - let xform_ret_ty = self.resolve_vars_if_possible(&xform_ret_ty); + let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty); debug!( "comparing return_ty {:?} with xform ret ty {:?}", return_ty, probe.xform_ret_ty @@ -1605,7 +1606,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Erase any late-bound regions from the method and substitute // in the values from the substitution. - let xform_fn_sig = self.erase_late_bound_regions(&fn_sig); + let xform_fn_sig = self.erase_late_bound_regions(fn_sig); if generics.params.is_empty() { xform_fn_sig.subst(self.tcx, substs) @@ -1673,7 +1674,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T + fn erase_late_bound_regions<T>(&self, value: ty::Binder<T>) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 46afe4892db..3d5ce57a491 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) => { let tcx = self.tcx; - let actual = self.resolve_vars_if_possible(&rcvr_ty); + let actual = self.resolve_vars_if_possible(rcvr_ty); let ty_str = self.ty_to_string(actual); let is_method = mode == Mode::MethodCall; let item_kind = if is_method { @@ -870,7 +870,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) { let output_ty = match self.infcx.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 169ad0df3a5..b242900a122 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -362,7 +362,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDe /// conclude that we don't have a defining use of `MyItem`. By mapping inference /// variables back to the actual generic parameters, we will correctly see that /// we have a defining use of `MyItem` -fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T +fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: T) -> T where T: TypeFoldable<'tcx>, { @@ -510,15 +510,15 @@ fn typeck_with_fallback<'tcx>( check_abi(tcx, span, fn_sig.abi()); // Compute the fty from point of view of inside the fn. - let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), &fn_sig); + let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = inh.normalize_associated_types_in( body.value.span, body_id.hir_id, param_env, - &fn_sig, + fn_sig, ); - let fn_sig = fixup_opaque_types(tcx, &fn_sig); + let fn_sig = fixup_opaque_types(tcx, fn_sig); let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; fcx @@ -543,11 +543,11 @@ fn typeck_with_fallback<'tcx>( _ => fallback(), }); - let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); + let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) + fcx.instantiate_opaque_types_from_value(id, expected_type, body.value.span) } else { expected_type }; diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 247b5256726..854bc70108f 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -660,7 +660,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method.sig.output() } Err(()) => { - let actual = self.resolve_vars_if_possible(&operand_ty); + let actual = self.resolve_vars_if_possible(operand_ty); if !actual.references_error() { let mut err = struct_span_err!( self.tcx.sess, @@ -983,7 +983,7 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::Param(_) = ty.kind() { self.0.push(ty); } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 6489b7838d6..a729912126e 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -149,6 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. + #[instrument(skip(self, ti))] fn check_pat( &self, pat: &'tcx Pat<'tcx>, @@ -156,8 +157,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_bm: BindingMode, ti: TopInfo<'tcx>, ) { - debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); - let path_res = match &pat.kind { PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), _ => None, @@ -398,6 +397,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(_, inner_ty, _) = expected.kind() { if matches!(inner_ty.kind(), ty::Slice(_)) { let tcx = self.tcx; + trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); + self.typeck_results + .borrow_mut() + .treat_byte_string_as_slice + .insert(lt.hir_id.local_id); pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); } } @@ -459,7 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Now that we know the types can be unified we find the unified type // and use it to type the entire expression. - let common_type = self.resolve_vars_if_possible(&lhs_ty.or(rhs_ty).unwrap_or(expected)); + let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected)); // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x, y| { diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 7b31b9f3915..b8b98cef763 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -229,7 +229,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_vars_if_possible(&unresolved_ty) + self.resolve_vars_if_possible(unresolved_ty) } /// Try to resolve the type for the given node. diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index e9dfef718fd..019fa78fb1e 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -39,10 +39,21 @@ use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::UpvarRegion; -use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; +use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind}; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_span::sym; use rustc_span::{Span, Symbol}; -use std::collections::hash_map::Entry; + +/// Describe the relationship between the paths of two places +/// eg: +/// - `foo` is ancestor of `foo.bar.baz` +/// - `foo.bar.baz` is an descendant of `foo.bar` +/// - `foo.bar` and `foo.baz` are divergent +enum PlaceAncestryRelation { + Ancestor, + Descendant, + Divergent, +} impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -111,40 +122,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> = - FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); - for (&var_hir_id, _) in upvars.iter() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: closure_def_id.expect_local(), - }; - debug!("seed upvar_id {:?}", upvar_id); - // Adding the upvar Id to the list of Upvars, which will be added - // to the map for the closure at the end of the for loop. - closure_captures.insert(var_hir_id, upvar_id); - - let capture_kind = match capture_clause { - hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), - hir::CaptureBy::Ref => { - let origin = UpvarRegion(upvar_id, span); - let upvar_region = self.next_region_var(origin); - let upvar_borrow = - ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; - ty::UpvarCapture::ByRef(upvar_borrow) - } - }; + let local_def_id = closure_def_id.expect_local(); - self.typeck_results.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); - } - // Add the vector of upvars to the map keyed with the closure id. - // This gives us an easier access to them without having to call - // tcx.upvars again.. - if !closure_captures.is_empty() { - self.typeck_results - .borrow_mut() - .closure_captures - .insert(closure_def_id, closure_captures); + let mut capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>> = + Default::default(); + if !self.tcx.features().capture_disjoint_fields { + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + for (&var_hir_id, _) in upvars.iter() { + let place = self.place_for_root_variable(local_def_id, var_hir_id); + + debug!("seed place {:?}", place); + + let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id); + let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span); + let info = ty::CaptureInfo { expr_id: None, capture_kind }; + + capture_information.insert(place, info); + } } } @@ -153,9 +147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut delegate = InferBorrowKind { fcx: self, closure_def_id, + closure_span: span, + capture_clause, current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM, current_origin: None, - adjust_upvar_captures: ty::UpvarCaptureMap::default(), + capture_information, }; euv::ExprUseVisitor::new( &mut delegate, @@ -166,6 +162,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .consume_body(body); + debug!( + "For closure={:?}, capture_information={:#?}", + closure_def_id, delegate.capture_information + ); + self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span); + if let Some(closure_substs) = infer_kind { // Unify the (as yet unbound) type variable in the closure // substs with the kind we inferred. @@ -182,7 +184,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.typeck_results.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures); + self.compute_min_captures(closure_def_id, delegate); + self.log_closure_min_capture_info(closure_def_id, span); + + self.min_captures_to_closure_captures_bridge(closure_def_id); // Now that we've analyzed the closure, we know how each // variable is borrowed, and we know what traits the closure @@ -226,15 +231,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let closure_def_id = tcx.hir().local_def_id(closure_id); - tcx.upvars_mentioned(closure_def_id) + self.typeck_results + .borrow() + .closure_captures + .get(&closure_def_id.to_def_id()) .iter() .flat_map(|upvars| { upvars.iter().map(|(&var_hir_id, _)| { let upvar_ty = self.node_ty(var_hir_id); - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: closure_def_id, - }; + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id); let capture = self.typeck_results.borrow().upvar_capture(upvar_id); debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); @@ -250,6 +255,296 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect() } + + /// Bridge for closure analysis + /// ---------------------------- + /// + /// For closure with DefId `c`, the bridge converts structures required for supporting RFC 2229, + /// to structures currently used in the compiler for handling closure captures. + /// + /// For example the following structure will be converted: + /// + /// closure_min_captures + /// foo -> [ {foo.x, ImmBorrow}, {foo.y, MutBorrow} ] + /// bar -> [ {bar.z, ByValue}, {bar.q, MutBorrow} ] + /// + /// to + /// + /// 1. closure_captures + /// foo -> UpvarId(foo, c), bar -> UpvarId(bar, c) + /// + /// 2. upvar_capture_map + /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue + fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) { + let mut closure_captures: FxIndexMap<hir::HirId, ty::UpvarId> = Default::default(); + let mut upvar_capture_map = ty::UpvarCaptureMap::default(); + + if let Some(min_captures) = + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) + { + for (var_hir_id, min_list) in min_captures.iter() { + for captured_place in min_list { + let place = &captured_place.place; + let capture_info = captured_place.info; + + let upvar_id = match place.base { + PlaceBase::Upvar(upvar_id) => upvar_id, + base => bug!("Expected upvar, found={:?}", base), + }; + + assert_eq!(upvar_id.var_path.hir_id, *var_hir_id); + assert_eq!(upvar_id.closure_expr_id, closure_def_id.expect_local()); + + closure_captures.insert(*var_hir_id, upvar_id); + + let new_capture_kind = if let Some(capture_kind) = + upvar_capture_map.get(&upvar_id) + { + // upvar_capture_map only stores the UpvarCapture (CaptureKind), + // so we create a fake capture info with no expression. + let fake_capture_info = + ty::CaptureInfo { expr_id: None, capture_kind: capture_kind.clone() }; + determine_capture_info(fake_capture_info, capture_info).capture_kind + } else { + capture_info.capture_kind + }; + upvar_capture_map.insert(upvar_id, new_capture_kind); + } + } + } + debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures); + debug!( + "For closure_def_id={:?}, upvar_capture_map={:#?}", + closure_def_id, upvar_capture_map + ); + + if !closure_captures.is_empty() { + self.typeck_results + .borrow_mut() + .closure_captures + .insert(closure_def_id, closure_captures); + + self.typeck_results.borrow_mut().upvar_capture_map.extend(upvar_capture_map); + } + } + + /// Analyzes the information collected by `InferBorrowKind` to compute the min number of + /// Places (and corresponding capture kind) that we need to keep track of to support all + /// the required captured paths. + /// + /// Eg: + /// ```rust,no_run + /// struct Point { x: i32, y: i32 } + /// + /// let s: String; // hir_id_s + /// let mut p: Point; // his_id_p + /// let c = || { + /// println!("{}", s); // L1 + /// p.x += 10; // L2 + /// println!("{}" , p.y) // L3 + /// println!("{}", p) // L4 + /// drop(s); // L5 + /// }; + /// ``` + /// and let hir_id_L1..5 be the expressions pointing to use of a captured variable on + /// the lines L1..5 respectively. + /// + /// InferBorrowKind results in a structure like this: + /// + /// ``` + /// { + /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue), + /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow)) + /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow)) + /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow)) + /// ``` + /// + /// After the min capture analysis, we get: + /// ``` + /// { + /// hir_id_s -> [ + /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue) + /// ], + /// hir_id_p -> [ + /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)), + /// ], + /// ``` + fn compute_min_captures( + &self, + closure_def_id: DefId, + inferred_info: InferBorrowKind<'_, 'tcx>, + ) { + let mut root_var_min_capture_list: ty::RootVariableMinCaptureList<'_> = Default::default(); + + for (place, capture_info) in inferred_info.capture_information.into_iter() { + let var_hir_id = match place.base { + PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected upvar, found={:?}", base), + }; + + // Arrays are captured in entirety, drop Index projections and projections + // after Index projections. + let first_index_projection = + place.projections.split(|proj| ProjectionKind::Index == proj.kind).next(); + let place = Place { + base_ty: place.base_ty, + base: place.base, + projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()), + }; + + let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { + None => { + let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }]; + root_var_min_capture_list.insert(var_hir_id, min_cap_list); + continue; + } + Some(min_cap_list) => min_cap_list, + }; + + // Go through each entry in the current list of min_captures + // - if ancestor is found, update it's capture kind to account for current place's + // capture information. + // + // - if descendant is found, remove it from the list, and update the current place's + // capture information to account for the descendants's capture kind. + // + // We can never be in a case where the list contains both an ancestor and a descendant + // Also there can only be ancestor but in case of descendants there might be + // multiple. + + let mut descendant_found = false; + let mut updated_capture_info = capture_info; + min_cap_list.retain(|possible_descendant| { + match determine_place_ancestry_relation(&place, &possible_descendant.place) { + // current place is ancestor of possible_descendant + PlaceAncestryRelation::Ancestor => { + descendant_found = true; + updated_capture_info = + determine_capture_info(updated_capture_info, possible_descendant.info); + false + } + + _ => true, + } + }); + + let mut ancestor_found = false; + if !descendant_found { + for possible_ancestor in min_cap_list.iter_mut() { + match determine_place_ancestry_relation(&place, &possible_ancestor.place) { + // current place is descendant of possible_ancestor + PlaceAncestryRelation::Descendant => { + ancestor_found = true; + possible_ancestor.info = + determine_capture_info(possible_ancestor.info, capture_info); + + // Only one ancestor of the current place will be in the list. + break; + } + _ => {} + } + } + } + + // Only need to insert when we don't have an ancestor in the existing min capture list + if !ancestor_found { + let captured_place = + ty::CapturedPlace { place: place.clone(), info: updated_capture_info }; + min_cap_list.push(captured_place); + } + } + + debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); + + if !root_var_min_capture_list.is_empty() { + self.typeck_results + .borrow_mut() + .closure_min_captures + .insert(closure_def_id, root_var_min_capture_list); + } + } + + fn init_capture_kind( + &self, + capture_clause: hir::CaptureBy, + upvar_id: ty::UpvarId, + closure_span: Span, + ) -> ty::UpvarCapture<'tcx> { + match capture_clause { + hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), + hir::CaptureBy::Ref => { + let origin = UpvarRegion(upvar_id, closure_span); + let upvar_region = self.next_region_var(origin); + let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; + ty::UpvarCapture::ByRef(upvar_borrow) + } + } + } + + fn place_for_root_variable( + &self, + closure_def_id: LocalDefId, + var_hir_id: hir::HirId, + ) -> Place<'tcx> { + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id); + + Place { + base_ty: self.node_ty(var_hir_id), + base: PlaceBase::Upvar(upvar_id), + projections: Default::default(), + } + } + + fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool { + self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) + } + + fn log_capture_analysis_first_pass( + &self, + closure_def_id: rustc_hir::def_id::DefId, + capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>, + closure_span: Span, + ) { + if self.should_log_capture_analysis(closure_def_id) { + let mut diag = + self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:"); + for (place, capture_info) in capture_information { + let capture_str = construct_capture_info_string(self.tcx, place, capture_info); + let output_str = format!("Capturing {}", capture_str); + + let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); + diag.span_note(span, &output_str); + } + diag.emit(); + } + } + + fn log_closure_min_capture_info(&self, closure_def_id: DefId, closure_span: Span) { + if self.should_log_capture_analysis(closure_def_id) { + if let Some(min_captures) = + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) + { + let mut diag = + self.tcx.sess.struct_span_err(closure_span, "Min Capture analysis includes:"); + + for (_, min_captures_for_var) in min_captures { + for capture in min_captures_for_var { + let place = &capture.place; + let capture_info = &capture.info; + + let capture_str = + construct_capture_info_string(self.tcx, place, capture_info); + let output_str = format!("Min Capture {}", capture_str); + + let span = + capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); + diag.span_note(span, &output_str); + } + } + diag.emit(); + } + } + } } struct InferBorrowKind<'a, 'tcx> { @@ -258,6 +553,10 @@ struct InferBorrowKind<'a, 'tcx> { // The def-id of the closure whose kind and upvar accesses are being inferred. closure_def_id: DefId, + closure_span: Span, + + capture_clause: hir::CaptureBy, + // The kind that we have inferred that the current closure // requires. Note that we *always* infer a minimal kind, even if // we don't always *use* that in the final result (i.e., sometimes @@ -270,9 +569,31 @@ struct InferBorrowKind<'a, 'tcx> { // variable access that caused us to do so. current_origin: Option<(Span, Symbol)>, - // For each upvar that we access, we track the minimal kind of - // access we need (ref, ref mut, move, etc). - adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, + /// For each Place that is captured by the closure, we track the minimal kind of + /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. + /// + /// Consider closure where s.str1 is captured via an ImmutableBorrow and + /// s.str2 via a MutableBorrow + /// + /// ```rust,no_run + /// struct SomeStruct { str1: String, str2: String } + /// + /// // Assume that the HirId for the variable definition is `V1` + /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") } + /// + /// let fix_s = |new_s2| { + /// // Assume that the HirId for the expression `s.str1` is `E1` + /// println!("Updating SomeStruct with str1=", s.str1); + /// // Assume that the HirId for the expression `*s.str2` is `E2` + /// s.str2 = new_s2; + /// }; + /// ``` + /// + /// For closure `fix_s`, (at a high level) the map contains + /// + /// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow } + /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } + capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>, } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { @@ -314,26 +635,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { var_name(tcx, upvar_id.var_path.hir_id), ); - let new_capture = ty::UpvarCapture::ByValue(Some(usage_span)); - match self.adjust_upvar_captures.entry(upvar_id) { - Entry::Occupied(mut e) => { - match e.get() { - // We always overwrite `ByRef`, since we require - // that the upvar be available by value. - // - // If we had a previous by-value usage without a specific - // span, use ours instead. Otherwise, keep the first span - // we encountered, since there isn't an obviously better one. - ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => { - e.insert(new_capture); - } - _ => {} - } - } - Entry::Vacant(e) => { - e.insert(new_capture); - } - } + let capture_info = ty::CaptureInfo { + expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)), + }; + + let curr_info = self.capture_information[&place_with_id.place]; + let updated_info = determine_capture_info(curr_info, capture_info); + + self.capture_information[&place_with_id.place] = updated_info; } /// Indicates that `place_with_id` is being directly mutated (e.g., assigned @@ -349,7 +659,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id ); - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if let PlaceBase::Upvar(_) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; for pointer_ty in place_with_id.place.deref_tys() { match pointer_ty.kind() { @@ -363,7 +673,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { _ => (), } } - self.adjust_upvar_deref(upvar_id, self.fcx.tcx.hir().span(diag_expr_id), borrow_kind); + self.adjust_upvar_deref(place_with_id, diag_expr_id, borrow_kind); } } @@ -377,24 +687,20 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id ); - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if let PlaceBase::Upvar(_) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. return; } // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref( - upvar_id, - self.fcx.tcx.hir().span(diag_expr_id), - ty::UniqueImmBorrow, - ); + self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow); } } fn adjust_upvar_deref( &mut self, - upvar_id: ty::UpvarId, - place_span: Span, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, borrow_kind: ty::BorrowKind, ) { assert!(match borrow_kind { @@ -411,15 +717,16 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { // upvar, then we need to modify the // borrow_kind of the upvar to make sure it // is inferred to mutable if necessary - self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); + self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind); - // also need to be in an FnMut closure since this is not an ImmBorrow - self.adjust_closure_kind( - upvar_id.closure_expr_id, - ty::ClosureKind::FnMut, - place_span, - var_name(tcx, upvar_id.var_path.hir_id), - ); + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + self.adjust_closure_kind( + upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir().span(diag_expr_id), + var_name(tcx, upvar_id.var_path.hir_id), + ); + } } /// We infer the borrow_kind with which to borrow upvars in a stack closure. @@ -427,37 +734,34 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. - fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { - let upvar_capture = self - .adjust_upvar_captures - .get(&upvar_id) - .copied() - .unwrap_or_else(|| self.fcx.typeck_results.borrow().upvar_capture(upvar_id)); + fn adjust_upvar_borrow_kind( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + kind: ty::BorrowKind, + ) { + let curr_capture_info = self.capture_information[&place_with_id.place]; + debug!( - "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", - upvar_id, upvar_capture, kind + "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})", + place_with_id, diag_expr_id, curr_capture_info, kind ); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - // Upvar is already by-value, the strongest criteria. - } - ty::UpvarCapture::ByRef(mut upvar_borrow) => { - match (upvar_borrow.kind, kind) { - // Take RHS: - (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow) - | (ty::UniqueImmBorrow, ty::MutBorrow) => { - upvar_borrow.kind = kind; - self.adjust_upvar_captures - .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); - } - // Take LHS: - (ty::ImmBorrow, ty::ImmBorrow) - | (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow) - | (ty::MutBorrow, _) => {} - } - } - } + if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { + // It's already captured by value, we don't need to do anything here + return; + } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind { + // Use the same region as the current capture information + // Doesn't matter since only one of the UpvarBorrow will be used. + let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region }; + + let capture_info = ty::CaptureInfo { + expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow), + }; + let updated_info = determine_capture_info(curr_capture_info, capture_info); + self.capture_information[&place_with_id.place] = updated_info; + }; } fn adjust_closure_kind( @@ -501,6 +805,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } } } + + fn init_capture_info_for_place( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + ) { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id); + + let capture_kind = + self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span); + + let expr_id = Some(diag_expr_id); + let capture_info = ty::CaptureInfo { expr_id, capture_kind }; + + debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info); + + self.capture_information.insert(place_with_id.place.clone(), capture_info); + } else { + debug!("Not upvar: {:?}", place_with_id); + } + } } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { @@ -514,7 +840,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { "consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})", place_with_id, diag_expr_id, mode ); - self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode); + if !self.capture_information.contains_key(&place_with_id.place) { + self.init_capture_info_for_place(place_with_id, diag_expr_id); + } + + self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id, mode); } fn borrow( @@ -528,6 +858,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id, bk ); + if !self.capture_information.contains_key(&place_with_id.place) { + self.init_capture_info_for_place(place_with_id, diag_expr_id); + } + match bk { ty::ImmBorrow => {} ty::UniqueImmBorrow => { @@ -541,10 +875,175 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); + + if !self.capture_information.contains_key(&assignee_place.place) { + self.init_capture_info_for_place(assignee_place, diag_expr_id); + } + self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id); } } +fn construct_capture_info_string( + tcx: TyCtxt<'_>, + place: &Place<'tcx>, + capture_info: &ty::CaptureInfo<'tcx>, +) -> String { + let variable_name = match place.base { + PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(), + _ => bug!("Capture_information should only contain upvars"), + }; + + let mut projections_str = String::new(); + for (i, item) in place.projections.iter().enumerate() { + let proj = match item.kind { + ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b), + ProjectionKind::Deref => String::from("Deref"), + ProjectionKind::Index => String::from("Index"), + ProjectionKind::Subslice => String::from("Subslice"), + }; + if i != 0 { + projections_str.push_str(","); + } + projections_str.push_str(proj.as_str()); + } + + let capture_kind_str = match capture_info.capture_kind { + ty::UpvarCapture::ByValue(_) => "ByValue".into(), + ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), + }; + format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str) +} + fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { tcx.hir().name(var_hir_id) } + +/// Helper function to determine if we need to escalate CaptureKind from +/// CaptureInfo A to B and returns the escalated CaptureInfo. +/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way) +/// +/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based +/// on the `CaptureInfo` containing an associated expression id. +/// +/// If both the CaptureKind and Expression are considered to be equivalent, +/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize +/// expressions reported back to the user as part of diagnostics based on which appears earlier +/// in the closure. This can be acheived simply by calling +/// `determine_capture_info(existing_info, current_info)`. This works out because the +/// expressions that occur earlier in the closure body than the current expression are processed before. +/// Consider the following example +/// ```rust,no_run +/// struct Point { x: i32, y: i32 } +/// let mut p: Point { x: 10, y: 10 }; +/// +/// let c = || { +/// p.x += 10; +/// // ^ E1 ^ +/// // ... +/// // More code +/// // ... +/// p.x += 10; // E2 +/// // ^ E2 ^ +/// }; +/// ``` +/// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow), +/// and both have an expression associated, however for diagnostics we prefer reporting +/// `E1` since it appears earlier in the closure body. When `E2` is being processed we +/// would've already handled `E1`, and have an existing capture_information for it. +/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return +/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics. +fn determine_capture_info( + capture_info_a: ty::CaptureInfo<'tcx>, + capture_info_b: ty::CaptureInfo<'tcx>, +) -> ty::CaptureInfo<'tcx> { + // If the capture kind is equivalent then, we don't need to escalate and can compare the + // expressions. + let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { + (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => { + // We don't need to worry about the spans being ignored here. + // + // The expr_id in capture_info corresponds to the span that is stored within + // ByValue(span) and therefore it gets handled with priortizing based on + // expressions below. + true + } + (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { + ref_a.kind == ref_b.kind + } + (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false, + }; + + if eq_capture_kind { + match (capture_info_a.expr_id, capture_info_b.expr_id) { + (Some(_), _) | (None, None) => capture_info_a, + (None, Some(_)) => capture_info_b, + } + } else { + // We select the CaptureKind which ranks higher based the following priority order: + // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow + match (capture_info_a.capture_kind, capture_info_b.capture_kind) { + (ty::UpvarCapture::ByValue(_), _) => capture_info_a, + (_, ty::UpvarCapture::ByValue(_)) => capture_info_b, + (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { + match (ref_a.kind, ref_b.kind) { + // Take LHS: + (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow) + | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a, + + // Take RHS: + (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow) + | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b, + + (ty::ImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) + | (ty::MutBorrow, ty::MutBorrow) => { + bug!("Expected unequal capture kinds"); + } + } + } + } + } +} + +/// Determines the Ancestry relationship of Place A relative to Place B +/// +/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B +/// `PlaceAncestryRelation::Descendant` implies Place A is descendant of Place B +/// `PlaceAncestryRelation::Divergent` implies neither of them is the ancestor of the other. +fn determine_place_ancestry_relation( + place_a: &Place<'tcx>, + place_b: &Place<'tcx>, +) -> PlaceAncestryRelation { + // If Place A and Place B, don't start off from the same root variable, they are divergent. + if place_a.base != place_b.base { + return PlaceAncestryRelation::Divergent; + } + + // Assume of length of projections_a = n + let projections_a = &place_a.projections; + + // Assume of length of projections_b = m + let projections_b = &place_b.projections; + + let mut same_initial_projections = true; + + for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) { + if proj_a != proj_b { + same_initial_projections = false; + break; + } + } + + if same_initial_projections { + // First min(n, m) projections are the same + // Select Ancestor/Descendant + if projections_b.len() >= projections_a.len() { + PlaceAncestryRelation::Ancestor + } else { + PlaceAncestryRelation::Descendant + } + } else { + PlaceAncestryRelation::Divergent + } +} diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 1e27357ce44..5dffe5107b5 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -403,12 +403,12 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, &ty); + let ty = fcx.normalize_associated_types_in(span, ty); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { let sig = fcx.tcx.fn_sig(item.def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( tcx, @@ -427,7 +427,7 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, &ty); + let ty = fcx.normalize_associated_types_in(span, ty); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -480,7 +480,7 @@ fn check_type_defn<'tcx, F>( let needs_drop_copy = || { packed && { let ty = variant.fields.last().unwrap().ty; - let ty = fcx.tcx.erase_regions(&ty); + let ty = fcx.tcx.erase_regions(ty); if ty.needs_infer() { fcx_tcx .sess @@ -592,7 +592,7 @@ fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = fcx.normalize_associated_types_in(span, &bound); + let normalized_bound = fcx.normalize_associated_types_in(span, bound); traits::wf::predicate_obligations( fcx, fcx.param_env, @@ -618,7 +618,7 @@ fn check_item_fn( for_id(tcx, item_id, span).with_fcx(|fcx, tcx| { let def_id = fcx.tcx.hir().local_def_id(item_id); let sig = fcx.tcx.fn_sig(def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); let mut implied_bounds = vec![]; check_fn_or_method( tcx, @@ -638,7 +638,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx, tcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in(ty_span, &ty); + let item_ty = fcx.normalize_associated_types_in(ty_span, ty); let mut forbid_unsized = true; if allow_foreign_ty { @@ -680,7 +680,7 @@ fn check_impl<'tcx>( // won't hold). let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); let trait_ref = - fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref); + fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref); let obligations = traits::wf::trait_obligations( fcx, fcx.param_env, @@ -695,7 +695,7 @@ fn check_impl<'tcx>( } None => { let self_ty = fcx.tcx.type_of(item_def_id); - let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); + let self_ty = fcx.normalize_associated_types_in(item.span, self_ty); fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, @@ -800,18 +800,20 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet<u32>, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { ControlFlow::BREAK } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ConstKind::Param(param) = c.val { self.params.insert(param.index); } @@ -845,7 +847,7 @@ fn check_where_clauses<'tcx, 'fcx>( // Note the subtle difference from how we handle `predicates` // below: there, we are not trying to prove those predicates // to be *true* but merely *well-formed*. - let pred = fcx.normalize_associated_types_in(sp, &pred); + let pred = fcx.normalize_associated_types_in(sp, pred); let cause = traits::ObligationCause::new(sp, fcx.body_id, traits::ItemObligation(def_id)); traits::Obligation::new(cause, fcx.param_env, pred) @@ -856,12 +858,12 @@ fn check_where_clauses<'tcx, 'fcx>( if let Some((mut return_ty, span)) = return_ty { if return_ty.has_infer_types_or_consts() { fcx.select_obligations_where_possible(false, |_| {}); - return_ty = fcx.resolve_vars_if_possible(&return_ty); + return_ty = fcx.resolve_vars_if_possible(return_ty); } check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty); } - let predicates = fcx.normalize_associated_types_in(span, &predicates); + let predicates = fcx.normalize_associated_types_in(span, predicates); debug!("check_where_clauses: predicates={:?}", predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); @@ -885,8 +887,8 @@ fn check_fn_or_method<'fcx, 'tcx>( def_id: DefId, implied_bounds: &mut Vec<Ty<'tcx>>, ) { - let sig = fcx.normalize_associated_types_in(span, &sig); - let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); + let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) { fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); @@ -1063,19 +1065,19 @@ fn check_method_receiver<'fcx, 'tcx>( let span = fn_sig.decl.inputs[0].span; let sig = fcx.tcx.fn_sig(method.def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); - let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); + let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig); debug!("check_method_receiver: sig={:?}", sig); - let self_ty = fcx.normalize_associated_types_in(span, &self_ty); - let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_ty)); + let self_ty = fcx.normalize_associated_types_in(span, self_ty); + let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty)); let receiver_ty = sig.inputs()[0]; - let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty); + let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty); let receiver_ty = - fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(receiver_ty)); + fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty)); if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { @@ -1307,7 +1309,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { let pred = obligation.predicate; // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_regions() { - let pred = fcx.normalize_associated_types_in(span, &pred); + let pred = fcx.normalize_associated_types_in(span, pred); let obligation = traits::Obligation::new( traits::ObligationCause::new(span, id, traits::TrivialBound), empty_env, @@ -1405,8 +1407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|field| { let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id)); - let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty); - let field_ty = self.resolve_vars_if_possible(&field_ty); + let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty); + let field_ty = self.resolve_vars_if_possible(field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); AdtField { ty: field_ty, span: field.ty.span } }) @@ -1429,7 +1431,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> { match self.tcx.impl_trait_ref(impl_def_id) { - Some(ref trait_ref) => { + Some(trait_ref) => { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.normalize_associated_types_in(span, trait_ref); @@ -1439,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => { // Inherent impl: take implied bounds from the `self` type. let self_ty = self.tcx.type_of(impl_def_id); - let self_ty = self.normalize_associated_types_in(span, &self_ty); + let self_ty = self.normalize_associated_types_in(span, self_ty); vec![self_ty] } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 5363702a5be..335f2cc2716 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -70,6 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.typeck_results.used_trait_imports = used_trait_imports; + wbcx.typeck_results.treat_byte_string_as_slice = + mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); + wbcx.typeck_results.closure_captures = mem::take(&mut self.typeck_results.borrow_mut().closure_captures); @@ -136,7 +139,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { match e.kind { hir::ExprKind::Unary(hir::UnOp::UnNeg | hir::UnOp::UnNot, ref inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); - let inner_ty = self.fcx.resolve_vars_if_possible(&inner_ty); + let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty); if inner_ty.is_scalar() { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); @@ -147,10 +150,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hir::ExprKind::Binary(ref op, ref lhs, ref rhs) | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { let lhs_ty = self.fcx.node_ty(lhs.hir_id); - let lhs_ty = self.fcx.resolve_vars_if_possible(&lhs_ty); + let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty); let rhs_ty = self.fcx.node_ty(rhs.hir_id); - let rhs_ty = self.fcx.resolve_vars_if_possible(&rhs_ty); + let rhs_ty = self.fcx.resolve_vars_if_possible(rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); @@ -209,7 +212,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { &format!("bad index {:?} for base: `{:?}`", index, base), ) }); - let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); + let index_ty = self.fcx.resolve_vars_if_possible(index_ty); if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize { // Remove the method call record @@ -313,14 +316,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; - let var_ty = self.resolve(&var_ty, &l.span); + let var_ty = self.resolve(var_ty, &l.span); self.write_ty_to_typeck_results(l.hir_id, var_ty); } fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { intravisit::walk_ty(self, hir_ty); let ty = self.fcx.node_ty(hir_ty.hir_id); - let ty = self.resolve(&ty, &hir_ty.span); + let ty = self.resolve(ty, &hir_ty.span); self.write_ty_to_typeck_results(hir_ty.hir_id, ty); } } @@ -432,7 +435,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local()); - let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id); debug_assert!(!instantiated_ty.has_escaping_bound_vars()); @@ -522,13 +525,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // Resolve the type of the node with id `node_id` let n_ty = self.fcx.node_ty(hir_id); - let n_ty = self.resolve(&n_ty, &span); + let n_ty = self.resolve(n_ty, &span); self.write_ty_to_typeck_results(hir_id, n_ty); debug!("node {:?} has type {:?}", hir_id, n_ty); // Resolve any substitutions if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { - let substs = self.resolve(&substs, &span); + let substs = self.resolve(substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); assert!(!substs.needs_infer() && !substs.has_placeholders()); self.typeck_results.node_substs_mut().insert(hir_id, substs); @@ -543,7 +546,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = self.resolve(&adjustment, &span); + let resolved_adjustment = self.resolve(adjustment, &span); debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment); } @@ -558,7 +561,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = self.resolve(&adjustment, &span); + let resolved_adjustment = self.resolve(adjustment, &span); debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment); } @@ -570,7 +573,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { + for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -584,12 +587,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - let ftys = self.resolve(ftys, &hir_id); + let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); } } - fn resolve<T>(&mut self, x: &T, span: &dyn Locatable) -> T + fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T where T: TypeFoldable<'tcx>, { @@ -681,8 +684,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match self.infcx.fully_resolve(&t) { - Ok(t) => self.infcx.tcx.erase_regions(&t), + match self.infcx.fully_resolve(t) { + Ok(t) => self.infcx.tcx.erase_regions(t), Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_type_error(t); @@ -698,8 +701,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match self.infcx.fully_resolve(&ct) { - Ok(ct) => self.infcx.tcx.erase_regions(&ct), + match self.infcx.fully_resolve(ct) { + Ok(ct) => self.infcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); self.report_const_error(ct); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b431de90369..dee0e6c2ebb 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -386,7 +386,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { "{}::{}", // Replace the existing lifetimes with a new named lifetime. self.tcx - .replace_late_bound_regions(&poly_trait_ref, |_| { + .replace_late_bound_regions(poly_trait_ref, |_| { self.tcx.mk_region(ty::ReEarlyBound( ty::EarlyBoundRegion { def_id: item_def_id, @@ -424,7 +424,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { format!( "{}::{}", // Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`. - self.tcx.anonymize_late_bound_regions(&poly_trait_ref).skip_binder(), + self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(), item_segment.ident ), Applicability::MaybeIncorrect, @@ -2062,7 +2062,7 @@ fn const_evaluatable_predicates_of<'tcx>( } impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { self.preds.insert(( ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 61d1efc837b..c4f4c8bc76b 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -637,7 +637,7 @@ fn infer_placeholder_type( } // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(&ty, &mut false, |r, _| match r { + tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index bae5bde7002..e389fd4d9f0 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -57,7 +57,7 @@ struct ParameterCollector { } impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective @@ -72,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } ControlFlow::CONTINUE } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { match c.val { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 57bd89b9d3d..1b51d5e0182 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -15,10 +15,10 @@ use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::ty::{self, adjustment, TyCtxt}; +use rustc_span::Span; use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; -use rustc_span::Span; /////////////////////////////////////////////////////////////////////////// // The Delegate trait @@ -73,6 +73,7 @@ pub enum MutateMode { // This is the code that actually walks the tree. pub struct ExprUseVisitor<'a, 'tcx> { mc: mc::MemCategorizationContext<'a, 'tcx>, + body_owner: LocalDefId, delegate: &'a mut dyn Delegate<'tcx>, } @@ -110,6 +111,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ) -> Self { ExprUseVisitor { mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results), + body_owner, delegate, } } @@ -329,8 +331,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_expr(base); } - hir::ExprKind::Closure(_, _, _, fn_decl_span, _) => { - self.walk_captures(expr, fn_decl_span); + hir::ExprKind::Closure(..) => { + self.walk_captures(expr); } hir::ExprKind::Box(ref base) => { @@ -529,7 +531,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); let tcx = self.tcx(); - let ExprUseVisitor { ref mc, ref mut delegate } = *self; + let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); @@ -569,36 +571,112 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { })); } - fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>, fn_decl_span: Span) { + /// Walk closure captures but using `closure_caputes` instead + /// of `closure_min_captures`. + /// + /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults + /// are written back. We don't currently writeback min_captures to + /// TypeckResults. + fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) { + // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18 + // is completed. + debug!("walk_captures_closure_captures({:?}), ", closure_expr); + + let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); + let cl_span = self.tcx().hir().span(closure_expr.hir_id); + + let captures = &self.mc.typeck_results.closure_captures[&closure_def_id]; + + for (&var_id, &upvar_id) in captures { + let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id); + let captured_place = + return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id)); + match upvar_capture { + ty::UpvarCapture::ByValue(_) => { + let mode = copy_or_move(&self.mc, &captured_place); + self.delegate.consume(&captured_place, captured_place.hir_id, mode); + } + ty::UpvarCapture::ByRef(upvar_borrow) => { + self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind); + } + } + } + } + + /// Handle the case where the current body contains a closure. + /// + /// When the current body being handled is a closure, then we must make sure that + /// - The parent closure only captures Places from the nested closure that are not local to it. + /// + /// In the following example the closures `c` only captures `p.x`` even though `incr` + /// is a capture of the nested closure + /// + /// ```rust,ignore(cannot-test-this-because-pseduo-code) + /// let p = ..; + /// let c = || { + /// let incr = 10; + /// let nested = || p.x += incr; + /// } + /// ``` + /// + /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing + /// closure as the DefId. + fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) { debug!("walk_captures({:?})", closure_expr); - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id); - if let Some(upvars) = self.tcx().upvars_mentioned(closure_def_id) { - for &var_id in upvars.keys() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_id }, - closure_expr_id: closure_def_id, - }; - let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id); - let captured_place = return_if_err!(self.cat_captured_var( - closure_expr.hir_id, - fn_decl_span, - var_id, - )); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - let mode = copy_or_move(&self.mc, &captured_place); - self.delegate.consume(&captured_place, captured_place.hir_id, mode); - } - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow( - &captured_place, - captured_place.hir_id, - upvar_borrow.kind, - ); + let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); + let upvars = self.tcx().upvars_mentioned(self.body_owner); + + // For purposes of this function, generator and closures are equivalent. + let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() { + ty::Closure(..) | ty::Generator(..) => true, + _ => false, + }; + + if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) + { + for (var_hir_id, min_list) in min_captures.iter() { + if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) { + // The nested closure might be capturing the current (enclosing) closure's local variables. + // We check if the root variable is ever mentioned within the enclosing closure, if not + // then for the current body (if it's a closure) these aren't captures, we will ignore them. + continue; + } + for captured_place in min_list { + let place = &captured_place.place; + let capture_info = captured_place.info; + + let upvar_id = if body_owner_is_closure { + // Mark the place to be captured by the enclosing closure + ty::UpvarId::new(*var_hir_id, self.body_owner) + } else { + ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local()) + }; + let place_with_id = PlaceWithHirId::new( + capture_info.expr_id.unwrap_or(closure_expr.hir_id), + place.base_ty, + PlaceBase::Upvar(upvar_id), + place.projections.clone(), + ); + + match capture_info.capture_kind { + ty::UpvarCapture::ByValue(_) => { + let mode = copy_or_move(&self.mc, &place_with_id); + self.delegate.consume(&place_with_id, place_with_id.hir_id, mode); + } + ty::UpvarCapture::ByRef(upvar_borrow) => { + self.delegate.borrow( + &place_with_id, + place_with_id.hir_id, + upvar_borrow.kind, + ); + } } } } + } else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) { + // Handle the case where clippy calls ExprUseVisitor after + self.walk_captures_closure_captures(closure_expr) } } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 4cf3efcf513..5db9ff9524d 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -165,7 +165,7 @@ fn get_impl_substs<'tcx>( // Conservatively use an empty `ParamEnv`. let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default()); - let impl2_substs = match infcx.fully_resolve(&impl2_substs) { + let impl2_substs = match infcx.fully_resolve(impl2_substs) { Ok(s) => s, Err(_) => { tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit(); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 30904091c1b..929c88455f0 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -61,6 +61,7 @@ This API is completely unstable and subject to change. #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] +#![feature(is_sorted)] #![feature(nll)] #![feature(or_patterns)] #![feature(try_blocks)] diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index f6ac7aa9155..9992094117d 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) } - fn resolve_vars_if_possible<T>(&self, value: &T) -> T + fn resolve_vars_if_possible<T>(&self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -142,7 +142,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult<Ty<'tcx>> { match ty { Some(ty) => { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if ty.references_error() || ty.is_ty_var() { debug!("resolve_type_vars_or_error: error from {:?}", ty); Err(()) @@ -274,7 +274,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>, { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); - let target = self.resolve_vars_if_possible(&adjustment.target); + let target = self.resolve_vars_if_possible(adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. |
