diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 28072f153a479..b48a7d29f5097 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -775,8 +775,9 @@ pub enum PatKind { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] #[derive(HashStable_Generic, Encodable, Decodable)] pub enum Mutability { - Mut, + // N.B. Order is deliberate, so that Not < Mut Not, + Mut, } impl Mutability { @@ -787,12 +788,39 @@ impl Mutability { } } - pub fn prefix_str(&self) -> &'static str { + /// Returns `""` (empty string) or `"mut "` depending on the mutability. + pub fn prefix_str(self) -> &'static str { match self { Mutability::Mut => "mut ", Mutability::Not => "", } } + + /// Returns `"&"` or `"&mut "` depending on the mutability. + pub fn ref_prefix_str(self) -> &'static str { + match self { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + } + } + + /// Returns `""` (empty string) or `"mutably "` depending on the mutability. + pub fn mutably_str(self) -> &'static str { + match self { + Mutability::Not => "", + Mutability::Mut => "mutably ", + } + } + + /// Return `true` if self is mutable + pub fn is_mut(self) -> bool { + matches!(self, Self::Mut) + } + + /// Return `true` if self is **not** mutable + pub fn is_not(self) -> bool { + matches!(self, Self::Not) + } } /// The kind of borrow in an `AddrOf` expression, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d1666dfbf6444..4ec943f33e230 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1781,14 +1781,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Given we are only considering `ImplicitSelf` types, we needn't consider // the case where we have a mutable pattern to a reference as that would // no longer be an `ImplicitSelf`. - TyKind::Rptr(_, mt) - if mt.ty.kind.is_implicit_self() && mt.mutbl == ast::Mutability::Mut => - { - hir::ImplicitSelfKind::MutRef - } - TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => { - hir::ImplicitSelfKind::ImmRef - } + TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl { + hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef, + hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef, + }, _ => hir::ImplicitSelfKind::None, } }), diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a53940070f7ea..919117651e2db 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -716,19 +716,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let moved_place = &self.move_data.move_paths[move_out.path].place; let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); let move_span = move_spans.args_or_use(); - let suggestion = if borrow_level == hir::Mutability::Mut { - "&mut ".to_string() - } else { - "&".to_string() - }; + let suggestion = borrow_level.ref_prefix_str().to_owned(); (move_span.shrink_to_lo(), suggestion) }) .collect(); err.multipart_suggestion_verbose( - &format!( - "consider {}borrowing {value_name}", - if borrow_level == hir::Mutability::Mut { "mutably " } else { "" } - ), + format!("consider {}borrowing {value_name}", borrow_level.mutably_str()), sugg, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7457369aa58cb..5122f9808ed29 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -389,13 +389,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // diagnostic: if the span starts with a mutable borrow of // a local variable, then just suggest the user remove it. PlaceRef { local: _, projection: [] } - if { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - snippet.starts_with("&mut ") - } else { - false - } - } => + if self + .infcx + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map_or(false, |snippet| snippet.starts_with("&mut ")) => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_suggestion( diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 077f33bb99cf7..a6bde88408497 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -257,9 +257,9 @@ pub(crate) fn data_id_for_alloc_id( mutability: rustc_hir::Mutability, ) -> DataId { cx.todo.push(TodoItem::Alloc(alloc_id)); - *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { - module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap() - }) + *cx.anon_allocs + .entry(alloc_id) + .or_insert_with(|| module.declare_anonymous_data(mutability.is_mut(), false).unwrap()) } fn data_id_for_static( @@ -343,12 +343,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } }; let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { - module - .declare_anonymous_data( - alloc.inner().mutability == rustc_hir::Mutability::Mut, - false, - ) - .unwrap() + module.declare_anonymous_data(alloc.inner().mutability.is_mut(), false).unwrap() }); (data_id, alloc, None) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index cf590a43826e5..2f5dd519b2600 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1500,7 +1500,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); let (pointer_count, underlying_ty) = match element_ty1.kind() { - ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { + ty::RawPtr(p) if p.ty == in_elem && p.mutbl.is_mut() => { (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 0c1819bb0c745..6e2fbf96cbfb3 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -130,10 +130,7 @@ impl hir::Pat<'_> { pub fn contains_explicit_ref_binding(&self) -> Option { let mut result = None; self.each_binding(|annotation, _, _, _| match annotation { - hir::BindingAnnotation::REF => match result { - None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not), - _ => {} - }, + hir::BindingAnnotation::REF if result.is_none() => result = Some(hir::Mutability::Not), hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut), _ => {} }); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d6a5736bbf443..193ecdb167880 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -370,7 +370,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { - if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) { + if mt_a.mutbl < mt_b.mutbl { infcx .err_ctxt() .report_mismatched_types( diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index d66b6585fb6f7..cc5114dba5efe 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -292,7 +292,7 @@ fn emit_newtype_suggestion_for_raw_ptr( diag: &mut Diagnostic, ) { if !self_ty.needs_subst() { - let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" }; + let mut_key = ptr_ty.mutbl.prefix_str(); let msg_sugg = "consider introducing a new wrapper type".to_owned(); let sugg = vec![ ( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d70ec94f5b61f..99a7f52efdb74 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -398,7 +398,7 @@ impl<'a> State<'a> { } hir::ForeignItemKind::Static(t, m) => { self.head("static"); - if m == hir::Mutability::Mut { + if m.is_mut() { self.word_space("mut"); } self.print_ident(item.ident); @@ -519,7 +519,7 @@ impl<'a> State<'a> { } hir::ItemKind::Static(ty, m, expr) => { self.head("static"); - if m == hir::Mutability::Mut { + if m.is_mut() { self.word_space("mut"); } self.print_ident(item.ident); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e93e8b0badaa9..e25a9e9036a15 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -574,8 +574,5 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn arms_contain_ref_bindings<'tcx>(arms: &'tcx [hir::Arm<'tcx>]) -> Option { - arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m { - hir::Mutability::Mut => 1, - hir::Mutability::Not => 0, - }) + arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max() } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 25b6cf4ef2e3e..1c14c1d35f799 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -257,15 +257,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded function call ops. - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; + // For initial two-phase borrow + // deployment, conservatively omit + // overloaded function call ops. + let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No); + autoref = Some(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[0], diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 5e1e44dcb6d15..1cea8c9dadce3 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { m_cast: ty::TypeAndMut<'tcx>, ) -> Result { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const - if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not { + if m_expr.mutbl >= m_cast.mutbl { if let ty::Array(ety, _) = m_expr.ty.kind() { // Due to the limitations of LLVM global constants, // region pointers end up pointing at copies of diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2c24b9ef14e85..1ceb07def72e7 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -202,7 +202,7 @@ fn check_panic_info_fn( let arg_is_panic_info = match *inputs[0].kind() { ty::Ref(region, ty, mutbl) => match *ty.kind() { ty::Adt(ref adt, _) => { - adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static() + adt.did() == panic_info_did && mutbl.is_not() && !region.is_static() } _ => false, }, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b6e37d9ec8e69..6b6d54db5062f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -108,11 +108,7 @@ fn coerce_mutbls<'tcx>( from_mutbl: hir::Mutability, to_mutbl: hir::Mutability, ) -> RelateResult<'tcx, ()> { - match (from_mutbl, to_mutbl) { - (hir::Mutability::Mut, hir::Mutability::Mut | hir::Mutability::Not) - | (hir::Mutability::Not, hir::Mutability::Not) => Ok(()), - (hir::Mutability::Not, hir::Mutability::Mut) => Err(TypeError::Mutability), - } + if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } } /// Do not require any adjustments, i.e. coerce `x -> x`. @@ -456,7 +452,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(err); }; - if ty == a && mt_a.mutbl == hir::Mutability::Not && autoderef.step_count() == 1 { + if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as // we started with. In that case, just skip it @@ -468,7 +464,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // `self.x` both have `&mut `type would be a move of // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. - assert_eq!(mutbl_b, hir::Mutability::Not); // can only coerce &T -> &U + assert!(mutbl_b.is_not()); // can only coerce &T -> &U return success(vec![], ty, obligations); } @@ -482,12 +478,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty::Ref(r_borrow, _, _) = ty.kind() else { span_bug!(span, "expected a ref type, got {:?}", ty); }; - let mutbl = match mutbl_b { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => { - AutoBorrowMutability::Mut { allow_two_phase_borrow: self.allow_two_phase } - } - }; + let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase); adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)), target: ty, @@ -556,15 +547,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let coercion = Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); - let mutbl = match mutbl_b { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // We don't allow two-phase borrows here, at least for initial - // implementation. If it happens that this coercion is a function argument, - // the reborrow in coerce_borrowed_ptr will pick it up. - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; + + // We don't allow two-phase borrows here, at least for initial + // implementation. If it happens that this coercion is a function argument, + // the reborrow in coerce_borrowed_ptr will pick it up. + let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No); + Some(( Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 934d12404427e..2106dce6f407e 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -19,6 +19,7 @@ use rustc_trait_selection::traits::ObligationCause; use super::method::probe; +use std::cmp::min; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -855,31 +856,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { - if mutability == hir::Mutability::Mut { + if mutability.is_mut() { // Suppressing this diagnostic, we'll properly print it in `check_expr_assign` return None; } } let sugg_expr = if needs_parens { format!("({src})") } else { src }; - return Some(match mutability { - hir::Mutability::Mut => ( - sp, - "consider mutably borrowing here".to_string(), - format!("{prefix}&mut {sugg_expr}"), - Applicability::MachineApplicable, - false, - false, - ), - hir::Mutability::Not => ( - sp, - "consider borrowing here".to_string(), - format!("{prefix}&{sugg_expr}"), - Applicability::MachineApplicable, - false, - false, - ), - }); + return Some(( + sp, + format!("consider {}borrowing here", mutability.mutably_str()), + format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()), + Applicability::MachineApplicable, + false, + false, + )); } } } @@ -937,51 +928,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Ok(src) = sm.span_to_snippet(sp) { let derefs = "*".repeat(steps); - if let Some((span, src, applicability)) = match mutbl_b { - hir::Mutability::Mut => { - let new_prefix = "&mut ".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(5); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - ( - sp, - format!("mut {derefs}"), - Applicability::Unspecified, - ) - }) - } - } - } - hir::Mutability::Not => { - let new_prefix = "&".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let lo = sp.lo() + BytePos(1); - let hi = sp.lo() + BytePos(5); - let sp = sp.with_lo(lo).with_hi(hi); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - } - } - } { + let old_prefix = mutbl_a.ref_prefix_str(); + let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs; + + let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| { + // skip `&` or `&mut ` if both mutabilities are mutable + let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); + // skip `&` or `&mut ` + let hi = sp.lo() + BytePos(old_prefix.len() as _); + let sp = sp.with_lo(lo).with_hi(hi); + + ( + sp, + format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }), + if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect } + ) + }); + + if let Some((span, src, applicability)) = suggestion { return Some(( span, "consider dereferencing".to_string(), @@ -1005,10 +969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the expression has `&`, removing it would fix the error prefix_span = prefix_span.with_hi(inner.span.lo()); expr = inner; - remove += match mutbl { - hir::Mutability::Not => "&", - hir::Mutability::Mut => "&mut ", - }; + remove.push_str(mutbl.ref_prefix_str()); steps -= 1; } else { break; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9299527ce1798..d7f875b285775 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2333,12 +2333,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty), - _ => return, - }; + let Some(output_ty) = self.get_impl_future_output_ty(ty) else { return; }; let mut add_label = true; - if let ty::Adt(def, _) = output_ty.skip_binder().kind() { + if let ty::Adt(def, _) = output_ty.kind() { // no field access on enum type if !def.is_enum() { if def diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index c0aff8f240f73..6c3526a71a328 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -345,8 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if annotation { let suggest_annotation = match expr.peel_drop_temps().kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&", - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ", + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(), _ => return true, }; let mut tuple_indexes = Vec::new(); @@ -925,15 +924,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match self.tcx.asyncness(fn_id.owner) { hir::IsAsync::Async => { let infcx = self.tcx.infer_ctxt().build(); - infcx - .get_impl_future_output_ty(ty) - .unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) - }) - .skip_binder() + infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }) } hir::IsAsync::NotAsync => ty, }; diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 30d2c63fd849a..50722c42a6c61 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -98,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { expr, scope, ty, self.expr_count, yield_data.span ); - if let Some((unresolved_type, unresolved_type_span)) = - self.fcx.unresolved_type_vars(&ty) + if let Some((unresolved_term, unresolved_type_span)) = + self.fcx.first_unresolved_const_or_ty_var(&ty) { // If unresolved type isn't a ty_var then unresolved_type_span is None let span = self @@ -108,13 +108,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { // If we encounter an int/float variable, then inference fallback didn't // finish due to some other error. Don't emit spurious additional errors. - if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = - unresolved_type.kind() + if let Some(unresolved_ty) = unresolved_term.ty() + && let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind() { self.fcx .tcx .sess - .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type)); + .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term)); } else { let note = format!( "the type is part of the {} because of this {}", @@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { ); self.fcx - .need_type_info_err_in_generator(self.kind, span, unresolved_type) + .need_type_info_err_in_generator(self.kind, span, unresolved_term) .span_note(yield_data.span, &*note) .emit(); } @@ -162,7 +162,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { expr.map(|e| e.span) ); if let Some((unresolved_type, unresolved_type_span)) = - self.fcx.unresolved_type_vars(&ty) + self.fcx.first_unresolved_const_or_ty_var(&ty) { debug!( "remained unresolved_type = {:?}, unresolved_type_span: {:?}", diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e968ccc11e55a..f50a16dcb236d 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -170,14 +170,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let base_ty = target; target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target }); - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // Method call receivers are the primary use case - // for two-phase borrows. - allow_two_phase_borrow: AllowTwoPhase::Yes, - }, - }; + + // Method call receivers are the primary use case + // for two-phase borrows. + let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes); + adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), target, @@ -202,7 +199,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => { target = match target.kind() { &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { - assert_eq!(mutbl, hir::Mutability::Mut); + assert!(mutbl.is_mut()); self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) } other => panic!("Cannot adjust receiver type {:?} to const ptr", other), diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 89746ce54a643..dea14dd93d6ac 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -5,7 +5,6 @@ use crate::{ use hir::def_id::DefId; use hir::HirId; use hir::ItemKind; -use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -88,14 +87,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Mut, - .. - }) => "&mut ", - Some(probe::AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Not, - .. - }) => "&", + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => { + mutbl.ref_prefix_str() + } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) @@ -386,8 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ", - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&", + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5ca74f713afe5..727fab9e7aa1e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1147,19 +1147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && assoc.kind == ty::AssocKind::Fn { let sig = self.tcx.fn_sig(assoc.def_id); - if let Some(first) = sig.inputs().skip_binder().get(0) { - if first.peel_refs() == rcvr_ty.peel_refs() { - None - } else { - Some(if first.is_region_ptr() { - if first.is_mutable_ptr() { "&mut " } else { "&" } - } else { - "" - }) - } - } else { + sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() { None - } + } else { + Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) + }) } else { None }; @@ -1960,7 +1952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) { let output_ty = match self.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(), + 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); @@ -2627,11 +2619,7 @@ fn print_disambiguation_help<'tcx>( let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) { let args = format!( "({}{})", - if rcvr_ty.is_region_ptr() { - if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" } - } else { - "" - }, + rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()), std::iter::once(receiver) .chain(args.iter()) .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index adc7a21f265a8..b12d84af4adbc 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -263,14 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let by_ref_binop = !op.node.is_by_value(); if is_assign == IsAssign::Yes || by_ref_binop { if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() { - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // Allow two-phase borrows for binops in initial deployment - // since they desugar to methods - allow_two_phase_borrow: AllowTwoPhase::Yes, - }, - }; + let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes); let autoref = Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[0], @@ -280,14 +273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if by_ref_binop { if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() { - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // Allow two-phase borrows for binops in initial deployment - // since they desugar to methods - allow_two_phase_borrow: AllowTwoPhase::Yes, - }, - }; + // Allow two-phase borrows for binops in initial deployment + // since they desugar to methods + let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes); + let autoref = Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[1], diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 2fe1b1d8999bc..decd317d9fc9b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -702,7 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut_var_suggestion = 'block: { - if !matches!(mutbl, ast::Mutability::Mut) { + if mutbl.is_not() { break 'block None; } @@ -749,7 +749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"), vec![ (pat.span.until(inner.span), "".to_owned()), - (ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())), + (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()), ], Applicability::MachineApplicable ); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ecb23e2be7de3..6b6be7359a599 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -74,7 +74,7 @@ use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::{ - self, error::TypeError, Binder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; @@ -339,16 +339,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( } impl<'tcx> InferCtxt<'tcx> { - pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option>> { - if let ty::Opaque(def_id, substs) = ty.kind() { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - // Future::Output - let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { + let ty::Opaque(def_id, substs) = *ty.kind() else { return None; }; - let bounds = self.tcx.bound_explicit_item_bounds(*def_id); + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) { - let output = predicate + self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( + |(predicate, _)| { + predicate .kind() .map_bound(|kind| match kind { ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) @@ -358,14 +357,10 @@ impl<'tcx> InferCtxt<'tcx> { } _ => None, }) - .transpose(); - if output.is_some() { - // We don't account for multiple `Future::Output = Ty` constraints. - return output; - } - } - } - None + .no_bound_vars() + .flatten() + }, + ) } } @@ -2055,8 +2050,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } match ( - self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder), - self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder), + self.get_impl_future_output_ty(exp_found.expected), + self.get_impl_future_output_ty(exp_found.found), ) { (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause .code() 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 7b3178e610fe4..8ff1639a3a24b 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 @@ -15,7 +15,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef}; @@ -508,10 +508,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { [ .., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ }, - ] => match mut_ { - AutoBorrowMutability::Mut { .. } => "&mut ", - AutoBorrowMutability::Not => "&", - }, + ] => hir::Mutability::from(*mut_).ref_prefix_str(), _ => "", }; @@ -571,7 +568,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, kind: hir::GeneratorKind, span: Span, - ty: Ty<'tcx>, + ty: ty::Term<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 67feb83faace6..cda9299dcb6e7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1421,16 +1421,15 @@ impl<'tcx> InferCtxt<'tcx> { value.fold_with(&mut r) } - /// Returns the first unresolved variable contained in `T`. In the - /// process of visiting `T`, this will resolve (where possible) - /// type variables in `T`, but it never constructs the final, - /// resolved type, so it's more efficient than - /// `resolve_vars_if_possible()`. - pub fn unresolved_type_vars(&self, value: &T) -> Option<(Ty<'tcx>, Option)> + /// Returns the first unresolved type or const variable contained in `T`. + pub fn first_unresolved_const_or_ty_var( + &self, + value: &T, + ) -> Option<(ty::Term<'tcx>, Option)> where T: TypeVisitable<'tcx>, { - value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() + value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value() } pub fn probe_const_var( diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4db4ff2388d77..8671f8d45a917 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,5 +1,6 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{FixupError, FixupResult, InferCtxt, Span}; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; @@ -110,48 +111,77 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// type variables that don't yet have a value. The first unresolved type is stored. /// It does not construct the fully resolved type (which might /// involve some hashing and so forth). -pub struct UnresolvedTypeFinder<'a, 'tcx> { +pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, } -impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { +impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - UnresolvedTypeFinder { infcx } + UnresolvedTypeOrConstFinder { infcx } } } -impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - type BreakTy = (Ty<'tcx>, Option); +impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { + type BreakTy = (ty::Term<'tcx>, Option); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); - if t.has_infer_types() { - if let ty::Infer(infer_ty) = *t.kind() { - // Since we called `shallow_resolve` above, this must - // be an (as yet...) unresolved inference variable. - let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let mut inner = self.infcx.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - if let TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), - span, - } = *ty_vars.var_origin(ty_vid) - { - Some(span) - } else { - None - } + if let ty::Infer(infer_ty) = *t.kind() { + // Since we called `shallow_resolve` above, this must + // be an (as yet...) unresolved inference variable. + let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { + let mut inner = self.infcx.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + if let TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), + span, + } = *ty_vars.var_origin(ty_vid) + { + Some(span) } else { None - }; - ControlFlow::Break((t, ty_var_span)) + } } else { - // Otherwise, visit its contents. - t.super_visit_with(self) - } + None + }; + ControlFlow::Break((t.into(), ty_var_span)) + } else if !t.has_non_region_infer() { + // All const/type variables in inference types must already be resolved, + // no need to visit the contents. + ControlFlow::CONTINUE } else { - // All type variables in inference types must already be resolved, - // - no need to visit the contents, continue visiting. + // Otherwise, keep visiting. + t.super_visit_with(self) + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + let ct = self.infcx.shallow_resolve(ct); + if let ty::ConstKind::Infer(i) = ct.kind() { + // Since we called `shallow_resolve` above, this must + // be an (as yet...) unresolved inference variable. + let ct_var_span = if let ty::InferConst::Var(vid) = i { + let mut inner = self.infcx.inner.borrow_mut(); + let ct_vars = &mut inner.const_unification_table(); + if let ConstVariableOrigin { + span, + kind: ConstVariableOriginKind::ConstParameterDefinition(_, _), + } = ct_vars.probe_value(vid).origin + { + Some(span) + } else { + None + } + } else { + None + }; + ControlFlow::Break((ct.into(), ct_var_span)) + } else if !ct.has_non_region_infer() { + // All const/type variables in inference types must already be resolved, + // no need to visit the contents. ControlFlow::CONTINUE + } else { + // Otherwise, keep visiting. + ct.super_visit_with(self) } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4b5aa3badda9f..7fb8ed8c23352 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1268,10 +1268,10 @@ declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) = + if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) = get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { - if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { + if from_mutbl < to_mutbl { cx.struct_span_lint( MUTABLE_TRANSMUTES, expr.span, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 36cdb50958caa..38b72ec923193 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2068,8 +2068,8 @@ rustc_queries! { remap_env_constness } - query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { - desc { "normalizing opaque types in `{:?}`", key } + query reveal_opaque_types_in_bounds(key: &'tcx ty::List>) -> &'tcx ty::List> { + desc { "revealing opaque types in `{:?}`", key } } query limits(key: ()) -> Limits { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index b8e6f0258d019..7036c4a7b27d6 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -159,6 +159,18 @@ pub enum AutoBorrowMutability { Not, } +impl AutoBorrowMutability { + /// Creates an `AutoBorrowMutability` from a mutability and allowance of two phase borrows. + /// + /// Note that when `mutbl.is_not()`, `allow_two_phase_borrow` is ignored + pub fn new(mutbl: hir::Mutability, allow_two_phase_borrow: AllowTwoPhase) -> Self { + match mutbl { + hir::Mutability::Not => Self::Not, + hir::Mutability::Mut => Self::Mut { allow_two_phase_borrow }, + } + } +} + impl From for hir::Mutability { fn from(m: AutoBorrowMutability) -> Self { match m { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e7dc2b36fafe9..7ad2a9edd4eff 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1747,7 +1747,7 @@ impl<'tcx> ParamEnv<'tcx> { } ParamEnv::new( - tcx.normalize_opaque_types(self.caller_bounds()), + tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All, self.constness(), ) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c1cf7896db59a..239b67bd22674 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -140,6 +140,15 @@ impl<'tcx> From> for GenericArg<'tcx> { } } +impl<'tcx> From> for GenericArg<'tcx> { + fn from(value: ty::Term<'tcx>) -> Self { + match value.unpack() { + ty::TermKind::Ty(t) => t.into(), + ty::TermKind::Const(c) => c.into(), + } + } +} + impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 6561c4c278d0e..717e5136e96d9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1248,9 +1248,9 @@ where #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub struct AlwaysRequiresDrop; -/// Normalizes all opaque types in the given value, replacing them +/// Reveals all opaque types in the given value, replacing them /// with their underlying types. -pub fn normalize_opaque_types<'tcx>( +pub fn reveal_opaque_types_in_bounds<'tcx>( tcx: TyCtxt<'tcx>, val: &'tcx ty::List>, ) -> &'tcx ty::List> { @@ -1287,7 +1287,7 @@ pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { - normalize_opaque_types, + reveal_opaque_types_in_bounds, is_doc_hidden, is_doc_notable_trait, is_intrinsic, diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 9fcba3e46f1d8..74048ff7da3bd 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -169,7 +169,7 @@ impl<'hir> Sig for hir::Ty<'hir> { let mut prefix = "&".to_owned(); prefix.push_str(&lifetime.name.ident().to_string()); prefix.push(' '); - if let hir::Mutability::Mut = mt.mutbl { + if mt.mutbl.is_mut() { prefix.push_str("mut "); }; @@ -332,7 +332,7 @@ impl<'hir> Sig for hir::Item<'hir> { match self.kind { hir::ItemKind::Static(ref ty, m, ref body) => { let mut text = "static ".to_owned(); - if m == hir::Mutability::Mut { + if m.is_mut() { text.push_str("mut "); } let name = self.ident.to_string(); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index b6378af7ba09c..2cca480f271c7 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -622,7 +622,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { }); match inner_ty.kind() { - ty::Str if *mutbl == hir::Mutability::Not => { + ty::Str if mutbl.is_not() => { match ct.kind() { ty::ConstKind::Value(valtree) => { let slice = 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 5c13b6400aebe..da6ca30cc9a32 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1055,7 +1055,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { ( mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), - matches!(mutability, hir::Mutability::Mut), + mutability.is_mut(), ) } else { (false, false) @@ -1344,7 +1344,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .sess .source_map() .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 { + if points_at_arg && mutability.is_not() && refs_number > 0 { err.span_suggestion_verbose( sp, "consider changing this borrow's mutability", diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 586462c0ef08e..98a5b761dedf5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1327,8 +1327,8 @@ a.test-arrow:hover { border-bottom: 1px solid; display: flex; height: 40px; - justify-content: center; - align-items: center; + justify-content: stretch; + align-items: stretch; z-index: 10; } #source-sidebar { @@ -1356,13 +1356,7 @@ a.test-arrow:hover { text-align: center; border: none; outline: none; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - /* work around button layout strangeness: https://stackoverflow.com/q/7271561 */ - width: 100%; + flex: 1 1; /* iOS button gradient: https://stackoverflow.com/q/5438567 */ -webkit-appearance: none; opacity: 1; diff --git a/src/test/rustdoc-json/enums/use_glob.rs b/src/test/rustdoc-json/enums/use_glob.rs new file mode 100644 index 0000000000000..62b8b832afdaa --- /dev/null +++ b/src/test/rustdoc-json/enums/use_glob.rs @@ -0,0 +1,18 @@ +// Regression test for + +#![feature(no_core)] +#![no_core] + +// @set Color = "$.index[*][?(@.name == 'Color')].id" +pub enum Color { + Red, + Green, + Blue, +} + +// @set use_Color = "$.index[*][?(@.kind == 'import')].id" +// @is "$.index[*][?(@.kind == 'import')].inner.id" $Color +// @is "$.index[*][?(@.kind == 'import')].inner.glob" true +pub use Color::*; + +// @ismany "$.index[*][?(@.name == 'use_glob')].inner.items[*]" $Color $use_Color diff --git a/src/test/rustdoc-json/enums/use_variant.rs b/src/test/rustdoc-json/enums/use_variant.rs new file mode 100644 index 0000000000000..5f0d2b9b1ec84 --- /dev/null +++ b/src/test/rustdoc-json/enums/use_variant.rs @@ -0,0 +1,15 @@ +#![feature(no_core)] +#![no_core] + +// @set AlwaysNone = "$.index[*][?(@.name == 'AlwaysNone')].id" +pub enum AlwaysNone { + // @set None = "$.index[*][?(@.name == 'None')].id" + None, +} +// @is "$.index[*][?(@.name == 'AlwaysNone')].inner.variants[*]" $None + +// @set use_None = "$.index[*][?(@.kind == 'import')].id" +// @is "$.index[*][?(@.kind == 'import')].inner.id" $None +pub use AlwaysNone::None; + +// @ismany "$.index[*][?(@.name == 'use_variant')].inner.items[*]" $AlwaysNone $use_None diff --git a/src/test/rustdoc-json/traits/trait_alias.rs b/src/test/rustdoc-json/traits/trait_alias.rs new file mode 100644 index 0000000000000..35db9296cddb2 --- /dev/null +++ b/src/test/rustdoc-json/traits/trait_alias.rs @@ -0,0 +1,30 @@ +// Regression test for +// ignore-tidy-linelength + +#![feature(trait_alias)] + +// @set Orig = "$.index[*][?(@.name == 'Orig')].id" +// @is "$.index[*][?(@.name == 'Orig')].kind" '"trait"' +pub trait Orig {} + +// @set Alias = "$.index[*][?(@.name == 'Alias')].id" +// @is "$.index[*][?(@.name == 'Alias')].kind" '"trait_alias"' +// @is "$.index[*][?(@.name == 'Alias')].inner.generics" '{"params": [], "where_predicates": []}' +// @count "$.index[*][?(@.name == 'Alias')].inner.params[*]" 1 +// @is "$.index[*][?(@.name == 'Alias')].inner.params[0].trait_bound.trait.id" $Orig +// @is "$.index[*][?(@.name == 'Alias')].inner.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.inner" '"i32"' +pub trait Alias = Orig; + +pub struct Struct; + +impl Orig for Struct {} + +// @is "$.index[*][?(@.name=='takes_alias')].inner.decl.inputs[0][1].kind" '"impl_trait"' +// @is "$.index[*][?(@.name=='takes_alias')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.id" $Alias +// @is "$.index[*][?(@.name=='takes_alias')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias +pub fn takes_alias(_: impl Alias) {} +// FIXME: Should the trait be mentioned in both the decl and generics? + +fn main() { + takes_alias(Struct); +} diff --git a/src/test/ui/generator/unresolved-ct-var.rs b/src/test/ui/generator/unresolved-ct-var.rs new file mode 100644 index 0000000000000..0a1570fc2395e --- /dev/null +++ b/src/test/ui/generator/unresolved-ct-var.rs @@ -0,0 +1,14 @@ +// incremental +// edition:2021 + +fn main() { + let _ = async { + let s = std::array::from_fn(|_| ()).await; + //~^ ERROR `[(); _]` is not a future + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + }; +} diff --git a/src/test/ui/generator/unresolved-ct-var.stderr b/src/test/ui/generator/unresolved-ct-var.stderr new file mode 100644 index 0000000000000..fdf00dfad7ab7 --- /dev/null +++ b/src/test/ui/generator/unresolved-ct-var.stderr @@ -0,0 +1,78 @@ +error[E0277]: `[(); _]` is not a future + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ---------------------------^^^^^^ + | | | + | | `[(); _]` is not a future + | | help: remove the `.await` + | this call returns `[(); _]` + | + = help: the trait `Future` is not implemented for `[(); _]` + = note: [(); _] must be a future or must implement `IntoFuture` to be awaited + = note: required for `[(); _]` to implement `IntoFuture` + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0698. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index a533e36712236..b395c6e7d2d62 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,7 +1,7 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; /// A univeral way to represent an [`ItemEnum`] or [`ItemKind`] -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub(crate) enum Kind { Module, ExternCrate, @@ -68,6 +68,22 @@ impl Kind { } } + pub fn can_appear_in_import(self) -> bool { + match self { + Kind::Variant => true, + Kind::Import => false, + other => other.can_appear_in_mod(), + } + } + + pub fn can_appear_in_glob_import(self) -> bool { + match self { + Kind::Module => true, + Kind::Enum => true, + _ => false, + } + } + pub fn can_appear_in_trait(self) -> bool { match self { Kind::AssocConst => true, @@ -111,8 +127,8 @@ impl Kind { pub fn is_variant(self) -> bool { matches!(self, Kind::Variant) } - pub fn is_trait(self) -> bool { - matches!(self, Kind::Trait) + pub fn is_trait_or_alias(self) -> bool { + matches!(self, Kind::Trait | Kind::TraitAlias) } pub fn is_type(self) -> bool { matches!(self, Kind::Struct | Kind::Enum | Kind::Union | Kind::Typedef) diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 9548276d826fb..5046ab9c7cbc1 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -103,9 +103,9 @@ impl<'a> Validator<'a> { fn check_import(&mut self, x: &'a Import) { if x.glob { - self.add_mod_id(x.id.as_ref().unwrap()); + self.add_glob_import_item_id(x.id.as_ref().unwrap()); } else if let Some(id) = &x.id { - self.add_mod_item_id(id); + self.add_import_item_id(id); } } @@ -266,7 +266,7 @@ impl<'a> Validator<'a> { fn check_path(&mut self, x: &'a Path, kind: PathKind) { match kind { - PathKind::Trait => self.add_trait_id(&x.id), + PathKind::Trait => self.add_trait_or_alias_id(&x.id), PathKind::Type => self.add_type_id(&x.id), } if let Some(args) = &x.args { @@ -391,8 +391,8 @@ impl<'a> Validator<'a> { self.add_id_checked(id, Kind::is_variant, "Variant"); } - fn add_trait_id(&mut self, id: &'a Id) { - self.add_id_checked(id, Kind::is_trait, "Trait"); + fn add_trait_or_alias_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_trait_or_alias, "Trait (or TraitAlias)"); } fn add_type_id(&mut self, id: &'a Id) { @@ -404,6 +404,15 @@ impl<'a> Validator<'a> { self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item"); } + /// Add an Id that can be `use`d + fn add_import_item_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::can_appear_in_import, "Import inner item"); + } + + fn add_glob_import_item_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::can_appear_in_glob_import, "Glob import inner item"); + } + /// Add an Id that appeared in a mod fn add_mod_item_id(&mut self, id: &'a Id) { self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item")