diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index dce31975dbc5d..4fbe68b8b6c54 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -45,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>( debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); let _: Result<_, ErrorGuaranteed> = try { - compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?; - compare_number_of_generics(tcx, impl_m, trait_m, false)?; - compare_generic_param_kinds(tcx, impl_m, trait_m, false)?; - compare_number_of_method_arguments(tcx, impl_m, trait_m)?; - compare_synthetic_generics(tcx, impl_m, trait_m)?; - compare_asyncness(tcx, impl_m, trait_m)?; + check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; compare_method_predicate_entailment( tcx, impl_m, @@ -61,6 +56,26 @@ pub(super) fn compare_impl_method<'tcx>( }; } +/// Checks a bunch of different properties of the impl/trait methods for +/// compatibility, such as asyncness, number of argument, self receiver kind, +/// and number of early- and late-bound generics. +fn check_method_is_structurally_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, + delay: bool, +) -> Result<(), ErrorGuaranteed> { + compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?; + compare_number_of_generics(tcx, impl_m, trait_m, delay)?; + compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?; + compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?; + compare_synthetic_generics(tcx, impl_m, trait_m, delay)?; + compare_asyncness(tcx, impl_m, trait_m, delay)?; + check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?; + Ok(()) +} + /// This function is best explained by example. Consider a trait with it's implementation: /// /// ```rust @@ -177,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>( let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let trait_m_predicates = tcx.predicates_of(trait_m.def_id); - // Check region bounds. - check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?; - // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter // environment. We can't just use `impl_env.caller_bounds`, @@ -534,6 +546,7 @@ fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { @@ -544,11 +557,14 @@ fn compare_asyncness<'tcx>( // We don't know if it's ok, but at least it's already an error. } _ => { - return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync { - span: tcx.def_span(impl_m.def_id), - method_name: trait_m.name, - trait_item_span: tcx.hir().span_if_local(trait_m.def_id), - })); + return Err(tcx + .sess + .create_err(crate::errors::AsyncTraitImplShouldBeAsync { + span: tcx.def_span(impl_m.def_id), + method_name: trait_m.name, + trait_item_span: tcx.hir().span_if_local(trait_m.def_id), + }) + .emit_unless(delay)); } }; } @@ -602,9 +618,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. - compare_number_of_generics(tcx, impl_m, trait_m, true)?; - compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; - check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?; + check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; let trait_to_impl_substs = impl_trait_ref.substs; @@ -1097,6 +1111,7 @@ fn compare_self_type<'tcx>( impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, + delay: bool, ) -> Result<(), ErrorGuaranteed> { // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected @@ -1145,7 +1160,7 @@ fn compare_self_type<'tcx>( } else { err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - return Err(err.emit()); + return Err(err.emit_unless(delay)); } (true, false) => { @@ -1166,7 +1181,7 @@ fn compare_self_type<'tcx>( err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - return Err(err.emit()); + return Err(err.emit_unless(delay)); } } @@ -1352,6 +1367,7 @@ fn compare_number_of_method_arguments<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { let impl_m_fty = tcx.fn_sig(impl_m.def_id); let trait_m_fty = tcx.fn_sig(trait_m.def_id); @@ -1422,7 +1438,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); - return Err(err.emit()); + return Err(err.emit_unless(delay)); } Ok(()) @@ -1432,6 +1448,7 @@ fn compare_synthetic_generics<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { // FIXME(chrisvittal) Clean up this function, list of FIXME items: // 1. Better messages for the span labels @@ -1551,7 +1568,7 @@ fn compare_synthetic_generics<'tcx>( } _ => unreachable!(), } - error_found = Some(err.emit()); + error_found = Some(err.emit_unless(delay)); } } if let Some(reported) = error_found { Err(reported) } else { Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 612d4ff3df843..5526dd4b007dd 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) if item.defaultness(tcx).has_value() { cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true) } else { - Vec::new() + vec![] } } - ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(), + ty::AssocKind::Fn => { + if !tcx.lower_impl_trait_in_trait_to_assoc_ty() + && item.defaultness(tcx).has_value() + && tcx.impl_method_has_trait_impl_trait_tys(item.def_id) + && let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id) + { + table.values().copied().flat_map(|ty| { + cgp::parameters_for(&ty.subst_identity(), true) + }).collect() + } else { + vec![] + } + } + ty::AssocKind::Const => vec![], } }) .collect(); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ff2989112af1a..7b05bff515148 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2124,12 +2124,16 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } let ty_generics = cx.tcx.generics_of(def_id); + let num_where_predicates = hir_generics + .predicates + .iter() + .filter(|predicate| predicate.in_where_clause()) + .count(); let mut bound_count = 0; let mut lint_spans = Vec::new(); let mut where_lint_spans = Vec::new(); - let mut dropped_predicate_count = 0; - let num_predicates = hir_generics.predicates.len(); + let mut dropped_where_predicate_count = 0; for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { let (relevant_lifetimes, bounds, predicate_span, in_where_clause) = match where_predicate { @@ -2186,8 +2190,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { bound_count += bound_spans.len(); let drop_predicate = bound_spans.len() == bounds.len(); - if drop_predicate { - dropped_predicate_count += 1; + if drop_predicate && in_where_clause { + dropped_where_predicate_count += 1; } if drop_predicate { @@ -2196,7 +2200,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } else if predicate_span.from_expansion() { // Don't try to extend the span if it comes from a macro expansion. where_lint_spans.push(predicate_span); - } else if i + 1 < num_predicates { + } else if i + 1 < num_where_predicates { // If all the bounds on a predicate were inferable and there are // further predicates, we want to eat the trailing comma. let next_predicate_span = hir_generics.predicates[i + 1].span(); @@ -2224,9 +2228,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } } - // If all predicates are inferable, drop the entire clause + // If all predicates in where clause are inferable, drop the entire clause // (including the `where`) - if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates + if hir_generics.has_where_clause_predicates + && dropped_where_predicate_count == num_where_predicates { let where_span = hir_generics.where_clause_span; // Extend the where clause back to the closing `>` of the diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6d8d99cfb5f1f..6bd030b13d1ce 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -8,6 +8,7 @@ //! For now, we are developing everything inside `rustc`, thus, we keep this module private. use crate::stable_mir::{self, ty::TyKind, Context}; +use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use tracing::debug; @@ -42,8 +43,8 @@ impl<'tcx> Context for Tables<'tcx> { .basic_blocks .iter() .map(|block| stable_mir::mir::BasicBlock { - terminator: rustc_terminator_to_terminator(block.terminator()), - statements: block.statements.iter().map(rustc_statement_to_statement).collect(), + terminator: block.terminator().stable(), + statements: block.statements.iter().map(mir::Statement::stable).collect(), }) .collect(), locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(), @@ -118,82 +119,95 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate { stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local } } -fn rustc_statement_to_statement( - s: &rustc_middle::mir::Statement<'_>, -) -> stable_mir::mir::Statement { - use rustc_middle::mir::StatementKind::*; - match &s.kind { - Assign(assign) => stable_mir::mir::Statement::Assign( - rustc_place_to_place(&assign.0), - rustc_rvalue_to_rvalue(&assign.1), - ), - FakeRead(_) => todo!(), - SetDiscriminant { .. } => todo!(), - Deinit(_) => todo!(), - StorageLive(_) => todo!(), - StorageDead(_) => todo!(), - Retag(_, _) => todo!(), - PlaceMention(_) => todo!(), - AscribeUserType(_, _) => todo!(), - Coverage(_) => todo!(), - Intrinsic(_) => todo!(), - ConstEvalCounter => todo!(), - Nop => stable_mir::mir::Statement::Nop, +pub trait Stable { + type T; + fn stable(&self) -> Self::T; +} + +impl<'tcx> Stable for mir::Statement<'tcx> { + type T = stable_mir::mir::Statement; + fn stable(&self) -> Self::T { + use rustc_middle::mir::StatementKind::*; + match &self.kind { + Assign(assign) => { + stable_mir::mir::Statement::Assign(assign.0.stable(), assign.1.stable()) + } + FakeRead(_) => todo!(), + SetDiscriminant { .. } => todo!(), + Deinit(_) => todo!(), + StorageLive(_) => todo!(), + StorageDead(_) => todo!(), + Retag(_, _) => todo!(), + PlaceMention(_) => todo!(), + AscribeUserType(_, _) => todo!(), + Coverage(_) => todo!(), + Intrinsic(_) => todo!(), + ConstEvalCounter => todo!(), + Nop => stable_mir::mir::Statement::Nop, + } } } -fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue { - use rustc_middle::mir::Rvalue::*; - match rvalue { - Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)), - Repeat(_, _) => todo!(), - Ref(_, _, _) => todo!(), - ThreadLocalRef(_) => todo!(), - AddressOf(_, _) => todo!(), - Len(_) => todo!(), - Cast(_, _, _) => todo!(), - BinaryOp(_, _) => todo!(), - CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( - rustc_bin_op_to_bin_op(bin_op), - rustc_op_to_op(&ops.0), - rustc_op_to_op(&ops.1), - ), - NullaryOp(_, _) => todo!(), - UnaryOp(un_op, op) => { - stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op)) +impl<'tcx> Stable for mir::Rvalue<'tcx> { + type T = stable_mir::mir::Rvalue; + fn stable(&self) -> Self::T { + use mir::Rvalue::*; + match self { + Use(op) => stable_mir::mir::Rvalue::Use(op.stable()), + Repeat(_, _) => todo!(), + Ref(_, _, _) => todo!(), + ThreadLocalRef(_) => todo!(), + AddressOf(_, _) => todo!(), + Len(_) => todo!(), + Cast(_, _, _) => todo!(), + BinaryOp(_, _) => todo!(), + CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( + bin_op.stable(), + ops.0.stable(), + ops.1.stable(), + ), + NullaryOp(_, _) => todo!(), + UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()), + Discriminant(_) => todo!(), + Aggregate(_, _) => todo!(), + ShallowInitBox(_, _) => todo!(), + CopyForDeref(_) => todo!(), } - Discriminant(_) => todo!(), - Aggregate(_, _) => todo!(), - ShallowInitBox(_, _) => todo!(), - CopyForDeref(_) => todo!(), } } -fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Operand { - use rustc_middle::mir::Operand::*; - match op { - Copy(place) => stable_mir::mir::Operand::Copy(rustc_place_to_place(place)), - Move(place) => stable_mir::mir::Operand::Move(rustc_place_to_place(place)), - Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()), +impl<'tcx> Stable for mir::Operand<'tcx> { + type T = stable_mir::mir::Operand; + fn stable(&self) -> Self::T { + use mir::Operand::*; + match self { + Copy(place) => stable_mir::mir::Operand::Copy(place.stable()), + Move(place) => stable_mir::mir::Operand::Move(place.stable()), + Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()), + } } } -fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place { - stable_mir::mir::Place { - local: place.local.as_usize(), - projection: format!("{:?}", place.projection), +impl<'tcx> Stable for mir::Place<'tcx> { + type T = stable_mir::mir::Place; + fn stable(&self) -> Self::T { + stable_mir::mir::Place { + local: self.local.as_usize(), + projection: format!("{:?}", self.projection), + } } } -fn rustc_unwind_to_unwind( - unwind: &rustc_middle::mir::UnwindAction, -) -> stable_mir::mir::UnwindAction { - use rustc_middle::mir::UnwindAction; - match unwind { - UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, - UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable, - UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate, - UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()), +impl Stable for mir::UnwindAction { + type T = stable_mir::mir::UnwindAction; + fn stable(&self) -> Self::T { + use rustc_middle::mir::UnwindAction; + match self { + UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, + UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable, + UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate, + UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()), + } } } @@ -202,168 +216,163 @@ fn rustc_assert_msg_to_msg<'tcx>( ) -> stable_mir::mir::AssertMessage { use rustc_middle::mir::AssertKind; match assert_message { - AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { - len: rustc_op_to_op(len), - index: rustc_op_to_op(index), - }, - AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( - rustc_bin_op_to_bin_op(bin_op), - rustc_op_to_op(op1), - rustc_op_to_op(op2), - ), - AssertKind::OverflowNeg(op) => { - stable_mir::mir::AssertMessage::OverflowNeg(rustc_op_to_op(op)) + AssertKind::BoundsCheck { len, index } => { + stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() } + } + AssertKind::Overflow(bin_op, op1, op2) => { + stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable()) } + AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), AssertKind::DivisionByZero(op) => { - stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op)) + stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) } AssertKind::RemainderByZero(op) => { - stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op)) + stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) } AssertKind::ResumedAfterReturn(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator( - generator, - )) + stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) } AssertKind::ResumedAfterPanic(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator( - generator, - )) + stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) } AssertKind::MisalignedPointerDereference { required, found } => { stable_mir::mir::AssertMessage::MisalignedPointerDereference { - required: rustc_op_to_op(required), - found: rustc_op_to_op(found), + required: required.stable(), + found: found.stable(), } } } } -fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp { - use rustc_middle::mir::BinOp; - match bin_op { - BinOp::Add => stable_mir::mir::BinOp::Add, - BinOp::Sub => stable_mir::mir::BinOp::Sub, - BinOp::Mul => stable_mir::mir::BinOp::Mul, - BinOp::Div => stable_mir::mir::BinOp::Div, - BinOp::Rem => stable_mir::mir::BinOp::Rem, - BinOp::BitXor => stable_mir::mir::BinOp::BitXor, - BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd, - BinOp::BitOr => stable_mir::mir::BinOp::BitOr, - BinOp::Shl => stable_mir::mir::BinOp::Shl, - BinOp::Shr => stable_mir::mir::BinOp::Shr, - BinOp::Eq => stable_mir::mir::BinOp::Eq, - BinOp::Lt => stable_mir::mir::BinOp::Lt, - BinOp::Le => stable_mir::mir::BinOp::Le, - BinOp::Ne => stable_mir::mir::BinOp::Ne, - BinOp::Ge => stable_mir::mir::BinOp::Ge, - BinOp::Gt => stable_mir::mir::BinOp::Gt, - BinOp::Offset => stable_mir::mir::BinOp::Offset, +impl Stable for mir::BinOp { + type T = stable_mir::mir::BinOp; + fn stable(&self) -> Self::T { + use mir::BinOp; + match self { + BinOp::Add => stable_mir::mir::BinOp::Add, + BinOp::Sub => stable_mir::mir::BinOp::Sub, + BinOp::Mul => stable_mir::mir::BinOp::Mul, + BinOp::Div => stable_mir::mir::BinOp::Div, + BinOp::Rem => stable_mir::mir::BinOp::Rem, + BinOp::BitXor => stable_mir::mir::BinOp::BitXor, + BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd, + BinOp::BitOr => stable_mir::mir::BinOp::BitOr, + BinOp::Shl => stable_mir::mir::BinOp::Shl, + BinOp::Shr => stable_mir::mir::BinOp::Shr, + BinOp::Eq => stable_mir::mir::BinOp::Eq, + BinOp::Lt => stable_mir::mir::BinOp::Lt, + BinOp::Le => stable_mir::mir::BinOp::Le, + BinOp::Ne => stable_mir::mir::BinOp::Ne, + BinOp::Ge => stable_mir::mir::BinOp::Ge, + BinOp::Gt => stable_mir::mir::BinOp::Gt, + BinOp::Offset => stable_mir::mir::BinOp::Offset, + } } } -fn rustc_un_op_to_un_op(unary_op: &rustc_middle::mir::UnOp) -> stable_mir::mir::UnOp { - use rustc_middle::mir::UnOp; - match unary_op { - UnOp::Not => stable_mir::mir::UnOp::Not, - UnOp::Neg => stable_mir::mir::UnOp::Neg, +impl Stable for mir::UnOp { + type T = stable_mir::mir::UnOp; + fn stable(&self) -> Self::T { + use mir::UnOp; + match self { + UnOp::Not => stable_mir::mir::UnOp::Not, + UnOp::Neg => stable_mir::mir::UnOp::Neg, + } } } -fn rustc_generator_to_generator( - generator: &rustc_hir::GeneratorKind, -) -> stable_mir::mir::GeneratorKind { - use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; - match generator { - GeneratorKind::Async(async_gen) => { - let async_gen = match async_gen { - AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block, - AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure, - AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn, - }; - stable_mir::mir::GeneratorKind::Async(async_gen) +impl Stable for rustc_hir::GeneratorKind { + type T = stable_mir::mir::GeneratorKind; + fn stable(&self) -> Self::T { + use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; + match self { + GeneratorKind::Async(async_gen) => { + let async_gen = match async_gen { + AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block, + AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure, + AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn, + }; + stable_mir::mir::GeneratorKind::Async(async_gen) + } + GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen, } - GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen, } } -fn rustc_inline_asm_operand_to_inline_asm_operand( - operand: &rustc_middle::mir::InlineAsmOperand<'_>, -) -> stable_mir::mir::InlineAsmOperand { - use rustc_middle::mir::InlineAsmOperand; +impl<'tcx> Stable for mir::InlineAsmOperand<'tcx> { + type T = stable_mir::mir::InlineAsmOperand; + fn stable(&self) -> Self::T { + use rustc_middle::mir::InlineAsmOperand; - let (in_value, out_place) = match operand { - InlineAsmOperand::In { value, .. } => (Some(rustc_op_to_op(value)), None), - InlineAsmOperand::Out { place, .. } => { - (None, place.map(|place| rustc_place_to_place(&place))) - } - InlineAsmOperand::InOut { in_value, out_place, .. } => { - (Some(rustc_op_to_op(in_value)), out_place.map(|place| rustc_place_to_place(&place))) - } - InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => (None, None), - }; + let (in_value, out_place) = match self { + InlineAsmOperand::In { value, .. } => (Some(value.stable()), None), + InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable())), + InlineAsmOperand::InOut { in_value, out_place, .. } => { + (Some(in_value.stable()), out_place.map(|place| place.stable())) + } + InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => (None, None), + }; - stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", operand) } + stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", self) } + } } -fn rustc_terminator_to_terminator( - terminator: &rustc_middle::mir::Terminator<'_>, -) -> stable_mir::mir::Terminator { - use rustc_middle::mir::TerminatorKind::*; - use stable_mir::mir::Terminator; - match &terminator.kind { - Goto { target } => Terminator::Goto { target: target.as_usize() }, - SwitchInt { discr, targets } => Terminator::SwitchInt { - discr: rustc_op_to_op(discr), - targets: targets - .iter() - .map(|(value, target)| stable_mir::mir::SwitchTarget { - value, - target: target.as_usize(), - }) - .collect(), - otherwise: targets.otherwise().as_usize(), - }, - Resume => Terminator::Resume, - Terminate => Terminator::Abort, - Return => Terminator::Return, - Unreachable => Terminator::Unreachable, - Drop { place, target, unwind, replace: _ } => Terminator::Drop { - place: rustc_place_to_place(place), - target: target.as_usize(), - unwind: rustc_unwind_to_unwind(unwind), - }, - Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { - Terminator::Call { - func: rustc_op_to_op(func), - args: args.iter().map(|arg| rustc_op_to_op(arg)).collect(), - destination: rustc_place_to_place(destination), - target: target.map(|t| t.as_usize()), - unwind: rustc_unwind_to_unwind(unwind), - } - } - Assert { cond, expected, msg, target, unwind } => Terminator::Assert { - cond: rustc_op_to_op(cond), - expected: *expected, - msg: rustc_assert_msg_to_msg(msg), - target: target.as_usize(), - unwind: rustc_unwind_to_unwind(unwind), - }, - InlineAsm { template, operands, options, line_spans, destination, unwind } => { - Terminator::InlineAsm { - template: format!("{:?}", template), - operands: operands +impl<'tcx> Stable for mir::Terminator<'tcx> { + type T = stable_mir::mir::Terminator; + fn stable(&self) -> Self::T { + use rustc_middle::mir::TerminatorKind::*; + use stable_mir::mir::Terminator; + match &self.kind { + Goto { target } => Terminator::Goto { target: target.as_usize() }, + SwitchInt { discr, targets } => Terminator::SwitchInt { + discr: discr.stable(), + targets: targets .iter() - .map(|operand| rustc_inline_asm_operand_to_inline_asm_operand(operand)) + .map(|(value, target)| stable_mir::mir::SwitchTarget { + value, + target: target.as_usize(), + }) .collect(), - options: format!("{:?}", options), - line_spans: format!("{:?}", line_spans), - destination: destination.map(|d| d.as_usize()), - unwind: rustc_unwind_to_unwind(unwind), + otherwise: targets.otherwise().as_usize(), + }, + Resume => Terminator::Resume, + Terminate => Terminator::Abort, + Return => Terminator::Return, + Unreachable => Terminator::Unreachable, + Drop { place, target, unwind, replace: _ } => Terminator::Drop { + place: place.stable(), + target: target.as_usize(), + unwind: unwind.stable(), + }, + Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { + Terminator::Call { + func: func.stable(), + args: args.iter().map(|arg| arg.stable()).collect(), + destination: destination.stable(), + target: target.map(|t| t.as_usize()), + unwind: unwind.stable(), + } + } + Assert { cond, expected, msg, target, unwind } => Terminator::Assert { + cond: cond.stable(), + expected: *expected, + msg: rustc_assert_msg_to_msg(msg), + target: target.as_usize(), + unwind: unwind.stable(), + }, + InlineAsm { template, operands, options, line_spans, destination, unwind } => { + Terminator::InlineAsm { + template: format!("{:?}", template), + operands: operands.iter().map(|operand| operand.stable()).collect(), + options: format!("{:?}", options), + line_spans: format!("{:?}", line_spans), + destination: destination.map(|d| d.as_usize()), + unwind: unwind.stable(), + } } + Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(), } - Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(), } } diff --git a/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs index 93df4221e61b2..f444a7f24bb72 100644 --- a/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs @@ -3,7 +3,7 @@ use super::{Target, TargetOptions}; pub fn target() -> Target { Target { - llvm_target: "loongarch64-unknown-none-softfloat".into(), + llvm_target: "loongarch64-unknown-none".into(), pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), arch: "loongarch64".into(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 2c793ea33dc88..190a78f6a8ecd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -23,7 +23,7 @@ use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; @@ -170,8 +170,8 @@ fn overlap<'tcx>( overlap_mode: OverlapMode, ) -> Option> { if overlap_mode.use_negative_impl() { - if negative_impl(tcx, impl1_def_id, impl2_def_id) - || negative_impl(tcx, impl2_def_id, impl1_def_id) + if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id) + || impl_intersection_has_negative_obligation(tcx, impl2_def_id, impl1_def_id) { return None; } @@ -198,13 +198,21 @@ fn overlap<'tcx>( let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); - let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; + // Equate the headers to find their intersection (the general type, with infer vars, + // that may apply both impls). + let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; debug!("overlap: unification check succeeded"); - if overlap_mode.use_implicit_negative() { - if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) { - return None; - } + if overlap_mode.use_implicit_negative() + && impl_intersection_has_impossible_obligation( + selcx, + param_env, + &impl1_header, + impl2_header, + equate_obligations, + ) + { + return None; } // We toggle the `leak_check` by using `skip_leak_check` when constructing the @@ -250,52 +258,38 @@ fn equate_impl_headers<'tcx>( result.map(|infer_ok| infer_ok.obligations).ok() } -/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including -/// where-clauses) If so, return false, otherwise return true, they are disjoint. -fn implicit_negative<'cx, 'tcx>( +/// Check if both impls can be satisfied by a common type by considering whether +/// any of either impl's obligations is not known to hold. +/// +/// For example, given these two impls: +/// `impl From for Box` (in my crate) +/// `impl From for Box where E: Error` (in libstd) +/// +/// After replacing both impl headers with inference vars (which happens before +/// this function is called), we get: +/// `Box: From` +/// `Box: From` +/// +/// This gives us `?E = MyLocalType`. We then certainly know that `MyLocalType: Error` +/// never holds in intercrate mode since a local impl does not exist, and a +/// downstream impl cannot be added -- therefore can consider the intersection +/// of the two impls above to be empty. +/// +/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`. +fn impl_intersection_has_impossible_obligation<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, impl1_header: &ty::ImplHeader<'tcx>, impl2_header: ty::ImplHeader<'tcx>, obligations: PredicateObligations<'tcx>, ) -> bool { - // There's no overlap if obligations are unsatisfiable or if the obligation negated is - // satisfied. - // - // For example, given these two impl headers: - // - // `impl<'a> From<&'a str> for Box` - // `impl From for Box where E: Error` - // - // So we have: - // - // `Box: From<&'?a str>` - // `Box: From` - // - // After equating the two headers: - // - // `Box = Box` - // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`. - // - // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't - // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because - // at some point an impl for `&'?a str: Error` could be added. - debug!( - "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})", - impl1_header, impl2_header, obligations - ); let infcx = selcx.infcx; - let opt_failing_obligation = impl1_header - .predicates - .iter() - .copied() - .chain(impl2_header.predicates) - .map(|p| infcx.resolve_vars_if_possible(p)) - .map(|p| Obligation { - cause: ObligationCause::dummy(), - param_env, - recursion_depth: 0, - predicate: p, + + let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates] + .into_iter() + .flatten() + .map(|&predicate| { + Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate) }) .chain(obligations) .find(|o| !selcx.predicate_may_hold_fatal(o)); @@ -308,9 +302,27 @@ fn implicit_negative<'cx, 'tcx>( } } -/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including -/// where-clauses) If so, return true, they are disjoint and false otherwise. -fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> bool { +/// Check if both impls can be satisfied by a common type by considering whether +/// any of first impl's obligations is known not to hold *via a negative predicate*. +/// +/// For example, given these two impls: +/// `struct MyCustomBox(Box);` +/// `impl From<&str> for MyCustomBox` (in my crate) +/// `impl From for MyCustomBox where E: Error` (in my crate) +/// +/// After replacing the second impl's header with inference vars, we get: +/// `MyCustomBox: From<&str>` +/// `MyCustomBox: From` +/// +/// This gives us `?E = &str`. We then try to prove the first impl's predicates +/// after negating, giving us `&str: !Error`. This is a negative impl provided by +/// libstd, and therefore we can guarantee for certain that libstd will never add +/// a positive impl for `&str: Error` (without it being a breaking change). +fn impl_intersection_has_negative_obligation( + tcx: TyCtxt<'_>, + impl1_def_id: DefId, + impl2_def_id: DefId, +) -> bool { debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); // Create an infcx, taking the predicates of impl1 as assumptions: @@ -336,57 +348,45 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b // Attempt to prove that impl2 applies, given all of the above. let selcx = &mut SelectionContext::new(&infcx); let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); - let (subject2, obligations) = + let (subject2, normalization_obligations) = impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| { ObligationCause::dummy() }); - !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) -} - -fn equate<'tcx>( - infcx: &InferCtxt<'tcx>, - impl_env: ty::ParamEnv<'tcx>, - subject1: ImplSubject<'tcx>, - subject2: ImplSubject<'tcx>, - obligations: impl Iterator>, - body_def_id: DefId, -) -> bool { - // do the impls unify? If not, not disjoint. - let Ok(InferOk { obligations: more_obligations, .. }) = + // do the impls unify? If not, then it's not currently possible to prove any + // obligations about their intersection. + let Ok(InferOk { obligations: equate_obligations, .. }) = infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2) else { debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); - return true; + return false; }; - let opt_failing_obligation = obligations - .into_iter() - .chain(more_obligations) - .find(|o| negative_impl_exists(infcx, o, body_def_id)); - - if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - false - } else { - true + for obligation in normalization_obligations.into_iter().chain(equate_obligations) { + if negative_impl_exists(&infcx, &obligation, impl1_def_id) { + debug!("overlap: obligation unsatisfiable {:?}", obligation); + return true; + } } + + false } -/// Try to prove that a negative impl exist for the given obligation and its super predicates. +/// Try to prove that a negative impl exist for the obligation or its supertraits. +/// +/// If such a negative impl exists, then the obligation definitely must not hold +/// due to coherence, even if it's not necessarily "knowable" in this crate. Any +/// valid impl downstream would not be able to exist due to the overlapping +/// negative impl. #[instrument(level = "debug", skip(infcx))] fn negative_impl_exists<'tcx>( infcx: &InferCtxt<'tcx>, o: &PredicateObligation<'tcx>, body_def_id: DefId, ) -> bool { - if resolve_negative_obligation(infcx.fork(), o, body_def_id) { - return true; - } - // Try to prove a negative obligation exists for super predicates for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) { - if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) { + if prove_negated_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) { return true; } } @@ -395,7 +395,7 @@ fn negative_impl_exists<'tcx>( } #[instrument(level = "debug", skip(infcx))] -fn resolve_negative_obligation<'tcx>( +fn prove_negated_obligation<'tcx>( infcx: InferCtxt<'tcx>, o: &PredicateObligation<'tcx>, body_def_id: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 25e5b5e17deff..5acd7b573dd9a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -365,7 +365,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let trait_ref = self.infcx.resolve_vars_if_possible( + stack.obligation.predicate.skip_binder().trait_ref, + ); if !trait_ref.references_error() { let self_ty = trait_ref.self_ty(); let (trait_desc, self_desc) = with_no_trimmed_paths!({ diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs index 99f058a901a31..6a6cbe905e464 100644 --- a/library/core/src/iter/sources/successors.rs +++ b/library/core/src/iter/sources/successors.rs @@ -22,7 +22,7 @@ where Successors { next: first, succ } } -/// An new iterator where each successive item is computed based on the preceding one. +/// A new iterator where each successive item is computed based on the preceding one. /// /// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 413b31282f7c9..75aa0c2b2a275 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.6 \ No newline at end of file +0.16.7 \ No newline at end of file diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index b26480f668b37..af1bc05ddb248 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -201,8 +201,8 @@ async function main(argv) { try { // This is more convenient that setting fields one by one. const args = [ - "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error", - "--allow-file-access-from-files", + "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"), + "--enable-fail-on-js-error", "--allow-file-access-from-files", ]; if (opts["debug"]) { debug = true; diff --git a/tests/rustdoc-gui/shortcuts.goml b/tests/rustdoc-gui/shortcuts.goml index 667df89ec9b00..2c61ee5428b86 100644 --- a/tests/rustdoc-gui/shortcuts.goml +++ b/tests/rustdoc-gui/shortcuts.goml @@ -13,7 +13,7 @@ press-key: "Escape" assert-css: ("#help-button .popover", {"display": "none"}) // Checking doc collapse and expand. // It should be displaying a "-": -assert-text: ("#toggle-all-docs", "[\u2212]") +assert-text: ("#toggle-all-docs", "[−]") press-key: "-" wait-for-text: ("#toggle-all-docs", "[+]") assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) @@ -23,9 +23,9 @@ assert-text: ("#toggle-all-docs", "[+]") assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) // Expanding now. press-key: "+" -wait-for-text: ("#toggle-all-docs", "[\u2212]") +wait-for-text: ("#toggle-all-docs", "[−]") assert-attribute: ("#toggle-all-docs", {"class": ""}) // Pressing it again shouldn't do anything. press-key: "+" -assert-text: ("#toggle-all-docs", "[\u2212]") +assert-text: ("#toggle-all-docs", "[−]") assert-attribute: ("#toggle-all-docs", {"class": ""}) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index d5dd511b1d31f..f8f73398d9b99 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -64,23 +64,23 @@ call-function: ("check-colors", { compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y")) // Check the `href` property so that users can treat anchors as links. assert-property: (".src-line-numbers > a:nth-child(1)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#1" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#1" +}, ENDS_WITH) assert-property: (".src-line-numbers > a:nth-child(2)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#2" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#2" +}, ENDS_WITH) assert-property: (".src-line-numbers > a:nth-child(3)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#3" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#3" +}, ENDS_WITH) assert-property: (".src-line-numbers > a:nth-child(4)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#4" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#4" +}, ENDS_WITH) assert-property: (".src-line-numbers > a:nth-child(5)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#5" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#5" +}, ENDS_WITH) assert-property: (".src-line-numbers > a:nth-child(6)", { - "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#6" -}) + "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#6" +}, ENDS_WITH) // Assert that the line numbers text is aligned to the right. assert-css: (".src-line-numbers", {"text-align": "right"}) diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr new file mode 100644 index 0000000000000..f604ada6ac760 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr @@ -0,0 +1,21 @@ +error[E0053]: method `early` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:58:27 + | +LL | fn early<'late, T>(_: &'late ()) {} + | - ^^^^^^^^^ + | | | + | | expected type parameter `T`, found `()` + | | help: change the parameter type to match the trait: `&'early T` + | this type parameter + | +note: type in trait + --> $DIR/method-signature-matches.rs:53:28 + | +LL | fn early<'early, T>(x: &'early T) -> impl Sized; + | ^^^^^^^^^ + = note: expected signature `fn(&'early T)` + found signature `fn(&())` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr new file mode 100644 index 0000000000000..d3183b92e8400 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr @@ -0,0 +1,20 @@ +error[E0053]: method `owo` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:14:15 + | +LL | fn owo(_: u8) {} + | ^^ + | | + | expected `()`, found `u8` + | help: change the parameter type to match the trait: `()` + | +note: type in trait + --> $DIR/method-signature-matches.rs:9:15 + | +LL | fn owo(x: ()) -> impl Sized; + | ^^ + = note: expected signature `fn(())` + found signature `fn(u8)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr new file mode 100644 index 0000000000000..80fda1c9fe14e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr @@ -0,0 +1,20 @@ +error[E0053]: method `owo` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:25:21 + | +LL | async fn owo(_: u8) {} + | ^^ + | | + | expected `()`, found `u8` + | help: change the parameter type to match the trait: `()` + | +note: type in trait + --> $DIR/method-signature-matches.rs:20:21 + | +LL | async fn owo(x: ()) {} + | ^^ + = note: expected signature `fn(()) -> _` + found signature `fn(u8) -> _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs index c848ee3f643de..294f93b30d0ee 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.rs +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs @@ -1,51 +1,62 @@ // edition: 2021 +// revisions: mismatch mismatch_async too_many too_few lt #![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] #![allow(incomplete_features)] +#[cfg(mismatch)] trait Uwu { fn owo(x: ()) -> impl Sized; } +#[cfg(mismatch)] impl Uwu for () { fn owo(_: u8) {} - //~^ ERROR method `owo` has an incompatible type for trait + //[mismatch]~^ ERROR method `owo` has an incompatible type for trait } +#[cfg(mismatch_async)] trait AsyncUwu { async fn owo(x: ()) {} } +#[cfg(mismatch_async)] impl AsyncUwu for () { async fn owo(_: u8) {} - //~^ ERROR method `owo` has an incompatible type for trait + //[mismatch_async]~^ ERROR method `owo` has an incompatible type for trait } +#[cfg(too_many)] trait TooMuch { fn calm_down_please() -> impl Sized; } +#[cfg(too_many)] impl TooMuch for () { fn calm_down_please(_: (), _: (), _: ()) {} - //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 + //[too_many]~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 } +#[cfg(too_few)] trait TooLittle { fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; } +#[cfg(too_few)] impl TooLittle for () { fn come_on_a_little_more_effort() {} - //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 + //[too_few]~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 } +#[cfg(lt)] trait Lifetimes { fn early<'early, T>(x: &'early T) -> impl Sized; } +#[cfg(lt)] impl Lifetimes for () { fn early<'late, T>(_: &'late ()) {} - //~^ ERROR method `early` has an incompatible type for trait + //[lt]~^ ERROR method `early` has an incompatible type for trait } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr deleted file mode 100644 index 3ec62020e6c89..0000000000000 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0053]: method `owo` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:11:15 - | -LL | fn owo(_: u8) {} - | ^^ - | | - | expected `()`, found `u8` - | help: change the parameter type to match the trait: `()` - | -note: type in trait - --> $DIR/method-signature-matches.rs:7:15 - | -LL | fn owo(x: ()) -> impl Sized; - | ^^ - = note: expected signature `fn(())` - found signature `fn(u8)` - -error[E0053]: method `owo` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:20:21 - | -LL | async fn owo(_: u8) {} - | ^^ - | | - | expected `()`, found `u8` - | help: change the parameter type to match the trait: `()` - | -note: type in trait - --> $DIR/method-signature-matches.rs:16:21 - | -LL | async fn owo(x: ()) {} - | ^^ - = note: expected signature `fn(()) -> _` - found signature `fn(u8) -> _` - -error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 - --> $DIR/method-signature-matches.rs:29:28 - | -LL | fn calm_down_please() -> impl Sized; - | ------------------------------------ trait requires 0 parameters -... -LL | fn calm_down_please(_: (), _: (), _: ()) {} - | ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3 - -error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 - --> $DIR/method-signature-matches.rs:38:5 - | -LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; - | ---------------- trait requires 3 parameters -... -LL | fn come_on_a_little_more_effort() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0 - -error[E0053]: method `early` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:47:27 - | -LL | fn early<'late, T>(_: &'late ()) {} - | - ^^^^^^^^^ - | | | - | | expected type parameter `T`, found `()` - | | help: change the parameter type to match the trait: `&'early T` - | this type parameter - | -note: type in trait - --> $DIR/method-signature-matches.rs:43:28 - | -LL | fn early<'early, T>(x: &'early T) -> impl Sized; - | ^^^^^^^^^ - = note: expected signature `fn(&'early T)` - found signature `fn(&())` - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0050, E0053. -For more information about an error, try `rustc --explain E0050`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr new file mode 100644 index 0000000000000..24bcfeb748fd0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr @@ -0,0 +1,12 @@ +error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 + --> $DIR/method-signature-matches.rs:47:5 + | +LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; + | ---------------- trait requires 3 parameters +... +LL | fn come_on_a_little_more_effort() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0050`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr new file mode 100644 index 0000000000000..616cbd2905c79 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr @@ -0,0 +1,12 @@ +error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 + --> $DIR/method-signature-matches.rs:36:28 + | +LL | fn calm_down_please() -> impl Sized; + | ------------------------------------ trait requires 0 parameters +... +LL | fn calm_down_please(_: (), _: (), _: ()) {} + | ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0050`. diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr new file mode 100644 index 0000000000000..bf088ae8b25cc --- /dev/null +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-lt.rs:10:6 + | +LL | impl<'a, T> Foo for T { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr new file mode 100644 index 0000000000000..bf088ae8b25cc --- /dev/null +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-lt.rs:10:6 + | +LL | impl<'a, T> Foo for T { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs new file mode 100644 index 0000000000000..f966be43a6ef8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs @@ -0,0 +1,16 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(return_position_impl_trait_in_trait)] + +trait Foo { + fn test() -> impl Sized; +} + +impl<'a, T> Foo for T { + //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + + fn test() -> &'a () { &() } +} + +fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed index 868bdf2e068d8..5058d61b58802 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed @@ -801,4 +801,10 @@ where yoo: &'a U } +// https://github.com/rust-lang/rust/issues/105150 +struct InferredWhereBoundWithInlineBound<'a, T: ?Sized> +{ + data: &'a T, +} + fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.rs b/tests/ui/rust-2018/edition-lint-infer-outlives.rs index 75783764ad6c9..3f63cb8e90030 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.rs +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.rs @@ -801,4 +801,12 @@ where yoo: &'a U } +// https://github.com/rust-lang/rust/issues/105150 +struct InferredWhereBoundWithInlineBound<'a, T: ?Sized> +//~^ ERROR outlives requirements can be inferred + where T: 'a, +{ + data: &'a T, +} + fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr index e655fb4842c71..dbf301fd8a1b7 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr @@ -10,6 +10,15 @@ note: the lint level is defined here LL | #![deny(explicit_outlives_requirements)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:805:56 + | +LL | struct InferredWhereBoundWithInlineBound<'a, T: ?Sized> + | ________________________________________________________^ +LL | | +LL | | where T: 'a, + | |________________^ help: remove this bound + error: outlives requirements can be inferred --> $DIR/edition-lint-infer-outlives.rs:26:31 | @@ -922,5 +931,5 @@ error: outlives requirements can be inferred LL | union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { | ^^^^^^^^ help: remove this bound -error: aborting due to 153 previous errors +error: aborting due to 154 previous errors