mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 19:17:43 +00:00
Auto merge of #112625 - matthiaskrgr:rollup-jcobj3g, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #112584 (loongarch64-none*: Remove environment component from llvm target) - #112600 (Introduce a `Stable` trait to translate MIR to SMIR) - #112605 (Improve docs/clean up negative overlap functions) - #112611 (Error on unconstrained lifetime in RPITIT) - #112612 (Fix explicit-outlives-requirements lint span) - #112613 (Fix rustdoc-gui tests on Windows) - #112620 (Fix small typo) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8c74a5d27c
@ -45,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>(
|
|||||||
debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
|
debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
|
||||||
|
|
||||||
let _: Result<_, ErrorGuaranteed> = try {
|
let _: Result<_, ErrorGuaranteed> = try {
|
||||||
compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?;
|
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
|
||||||
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)?;
|
|
||||||
compare_method_predicate_entailment(
|
compare_method_predicate_entailment(
|
||||||
tcx,
|
tcx,
|
||||||
impl_m,
|
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:
|
/// This function is best explained by example. Consider a trait with it's implementation:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -177,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||||||
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
|
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
|
||||||
let trait_m_predicates = tcx.predicates_of(trait_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
|
// Create obligations for each predicate declared by the impl
|
||||||
// definition in the context of the trait's parameter
|
// definition in the context of the trait's parameter
|
||||||
// environment. We can't just use `impl_env.caller_bounds`,
|
// environment. We can't just use `impl_env.caller_bounds`,
|
||||||
@ -534,6 +546,7 @@ fn compare_asyncness<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
trait_m: ty::AssocItem,
|
trait_m: ty::AssocItem,
|
||||||
|
delay: bool,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
|
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
|
||||||
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
|
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.
|
// 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 {
|
return Err(tcx
|
||||||
span: tcx.def_span(impl_m.def_id),
|
.sess
|
||||||
method_name: trait_m.name,
|
.create_err(crate::errors::AsyncTraitImplShouldBeAsync {
|
||||||
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
|
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`,
|
// First, check a few of the same things as `compare_impl_method`,
|
||||||
// just so we don't ICE during substitution later.
|
// just so we don't ICE during substitution later.
|
||||||
compare_number_of_generics(tcx, impl_m, trait_m, true)?;
|
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
|
||||||
compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
|
|
||||||
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
|
|
||||||
|
|
||||||
let trait_to_impl_substs = impl_trait_ref.substs;
|
let trait_to_impl_substs = impl_trait_ref.substs;
|
||||||
|
|
||||||
@ -1097,6 +1111,7 @@ fn compare_self_type<'tcx>(
|
|||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
trait_m: ty::AssocItem,
|
trait_m: ty::AssocItem,
|
||||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||||
|
delay: bool,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// Try to give more informative error messages about self typing
|
// Try to give more informative error messages about self typing
|
||||||
// mismatches. Note that any mismatch will also be detected
|
// mismatches. Note that any mismatch will also be detected
|
||||||
@ -1145,7 +1160,7 @@ fn compare_self_type<'tcx>(
|
|||||||
} else {
|
} else {
|
||||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||||
}
|
}
|
||||||
return Err(err.emit());
|
return Err(err.emit_unless(delay));
|
||||||
}
|
}
|
||||||
|
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
@ -1166,7 +1181,7 @@ fn compare_self_type<'tcx>(
|
|||||||
err.note_trait_signature(trait_m.name, trait_m.signature(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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
trait_m: ty::AssocItem,
|
trait_m: ty::AssocItem,
|
||||||
|
delay: bool,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let impl_m_fty = tcx.fn_sig(impl_m.def_id);
|
let impl_m_fty = tcx.fn_sig(impl_m.def_id);
|
||||||
let trait_m_fty = tcx.fn_sig(trait_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(())
|
Ok(())
|
||||||
@ -1432,6 +1448,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
trait_m: ty::AssocItem,
|
trait_m: ty::AssocItem,
|
||||||
|
delay: bool,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// FIXME(chrisvittal) Clean up this function, list of FIXME items:
|
// FIXME(chrisvittal) Clean up this function, list of FIXME items:
|
||||||
// 1. Better messages for the span labels
|
// 1. Better messages for the span labels
|
||||||
@ -1551,7 +1568,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
error_found = Some(err.emit());
|
error_found = Some(err.emit_unless(delay));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
|
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
|
||||||
|
@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
|
|||||||
if item.defaultness(tcx).has_value() {
|
if item.defaultness(tcx).has_value() {
|
||||||
cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true)
|
cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true)
|
||||||
} else {
|
} 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();
|
.collect();
|
||||||
|
@ -2124,12 +2124,16 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ty_generics = cx.tcx.generics_of(def_id);
|
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 bound_count = 0;
|
||||||
let mut lint_spans = Vec::new();
|
let mut lint_spans = Vec::new();
|
||||||
let mut where_lint_spans = Vec::new();
|
let mut where_lint_spans = Vec::new();
|
||||||
let mut dropped_predicate_count = 0;
|
let mut dropped_where_predicate_count = 0;
|
||||||
let num_predicates = hir_generics.predicates.len();
|
|
||||||
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
||||||
let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
|
let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
|
||||||
match where_predicate {
|
match where_predicate {
|
||||||
@ -2186,8 +2190,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||||||
bound_count += bound_spans.len();
|
bound_count += bound_spans.len();
|
||||||
|
|
||||||
let drop_predicate = bound_spans.len() == bounds.len();
|
let drop_predicate = bound_spans.len() == bounds.len();
|
||||||
if drop_predicate {
|
if drop_predicate && in_where_clause {
|
||||||
dropped_predicate_count += 1;
|
dropped_where_predicate_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if drop_predicate {
|
if drop_predicate {
|
||||||
@ -2196,7 +2200,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||||||
} else if predicate_span.from_expansion() {
|
} else if predicate_span.from_expansion() {
|
||||||
// Don't try to extend the span if it comes from a macro expansion.
|
// Don't try to extend the span if it comes from a macro expansion.
|
||||||
where_lint_spans.push(predicate_span);
|
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
|
// If all the bounds on a predicate were inferable and there are
|
||||||
// further predicates, we want to eat the trailing comma.
|
// further predicates, we want to eat the trailing comma.
|
||||||
let next_predicate_span = hir_generics.predicates[i + 1].span();
|
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`)
|
// (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;
|
let where_span = hir_generics.where_clause_span;
|
||||||
// Extend the where clause back to the closing `>` of the
|
// Extend the where clause back to the closing `>` of the
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
||||||
|
|
||||||
use crate::stable_mir::{self, ty::TyKind, Context};
|
use crate::stable_mir::{self, ty::TyKind, Context};
|
||||||
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@ -42,8 +43,8 @@ impl<'tcx> Context for Tables<'tcx> {
|
|||||||
.basic_blocks
|
.basic_blocks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|block| stable_mir::mir::BasicBlock {
|
.map(|block| stable_mir::mir::BasicBlock {
|
||||||
terminator: rustc_terminator_to_terminator(block.terminator()),
|
terminator: block.terminator().stable(),
|
||||||
statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
|
statements: block.statements.iter().map(mir::Statement::stable).collect(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).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 }
|
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_statement_to_statement(
|
pub trait Stable {
|
||||||
s: &rustc_middle::mir::Statement<'_>,
|
type T;
|
||||||
) -> stable_mir::mir::Statement {
|
fn stable(&self) -> Self::T;
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue {
|
impl<'tcx> Stable for mir::Statement<'tcx> {
|
||||||
use rustc_middle::mir::Rvalue::*;
|
type T = stable_mir::mir::Statement;
|
||||||
match rvalue {
|
fn stable(&self) -> Self::T {
|
||||||
Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)),
|
use rustc_middle::mir::StatementKind::*;
|
||||||
Repeat(_, _) => todo!(),
|
match &self.kind {
|
||||||
Ref(_, _, _) => todo!(),
|
Assign(assign) => {
|
||||||
ThreadLocalRef(_) => todo!(),
|
stable_mir::mir::Statement::Assign(assign.0.stable(), assign.1.stable())
|
||||||
AddressOf(_, _) => todo!(),
|
}
|
||||||
Len(_) => todo!(),
|
FakeRead(_) => todo!(),
|
||||||
Cast(_, _, _) => todo!(),
|
SetDiscriminant { .. } => todo!(),
|
||||||
BinaryOp(_, _) => todo!(),
|
Deinit(_) => todo!(),
|
||||||
CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
|
StorageLive(_) => todo!(),
|
||||||
rustc_bin_op_to_bin_op(bin_op),
|
StorageDead(_) => todo!(),
|
||||||
rustc_op_to_op(&ops.0),
|
Retag(_, _) => todo!(),
|
||||||
rustc_op_to_op(&ops.1),
|
PlaceMention(_) => todo!(),
|
||||||
),
|
AscribeUserType(_, _) => todo!(),
|
||||||
NullaryOp(_, _) => todo!(),
|
Coverage(_) => todo!(),
|
||||||
UnaryOp(un_op, op) => {
|
Intrinsic(_) => todo!(),
|
||||||
stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op))
|
ConstEvalCounter => todo!(),
|
||||||
|
Nop => stable_mir::mir::Statement::Nop,
|
||||||
}
|
}
|
||||||
Discriminant(_) => todo!(),
|
|
||||||
Aggregate(_, _) => todo!(),
|
|
||||||
ShallowInitBox(_, _) => todo!(),
|
|
||||||
CopyForDeref(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Operand {
|
impl<'tcx> Stable for mir::Rvalue<'tcx> {
|
||||||
use rustc_middle::mir::Operand::*;
|
type T = stable_mir::mir::Rvalue;
|
||||||
match op {
|
fn stable(&self) -> Self::T {
|
||||||
Copy(place) => stable_mir::mir::Operand::Copy(rustc_place_to_place(place)),
|
use mir::Rvalue::*;
|
||||||
Move(place) => stable_mir::mir::Operand::Move(rustc_place_to_place(place)),
|
match self {
|
||||||
Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()),
|
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!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
|
impl<'tcx> Stable for mir::Operand<'tcx> {
|
||||||
stable_mir::mir::Place {
|
type T = stable_mir::mir::Operand;
|
||||||
local: place.local.as_usize(),
|
fn stable(&self) -> Self::T {
|
||||||
projection: format!("{:?}", place.projection),
|
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_unwind_to_unwind(
|
impl<'tcx> Stable for mir::Place<'tcx> {
|
||||||
unwind: &rustc_middle::mir::UnwindAction,
|
type T = stable_mir::mir::Place;
|
||||||
) -> stable_mir::mir::UnwindAction {
|
fn stable(&self) -> Self::T {
|
||||||
use rustc_middle::mir::UnwindAction;
|
stable_mir::mir::Place {
|
||||||
match unwind {
|
local: self.local.as_usize(),
|
||||||
UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
|
projection: format!("{:?}", self.projection),
|
||||||
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 {
|
) -> stable_mir::mir::AssertMessage {
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
match assert_message {
|
match assert_message {
|
||||||
AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
|
AssertKind::BoundsCheck { len, index } => {
|
||||||
len: rustc_op_to_op(len),
|
stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() }
|
||||||
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::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) => {
|
AssertKind::DivisionByZero(op) => {
|
||||||
stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op))
|
stable_mir::mir::AssertMessage::DivisionByZero(op.stable())
|
||||||
}
|
}
|
||||||
AssertKind::RemainderByZero(op) => {
|
AssertKind::RemainderByZero(op) => {
|
||||||
stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op))
|
stable_mir::mir::AssertMessage::RemainderByZero(op.stable())
|
||||||
}
|
}
|
||||||
AssertKind::ResumedAfterReturn(generator) => {
|
AssertKind::ResumedAfterReturn(generator) => {
|
||||||
stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator(
|
stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable())
|
||||||
generator,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
AssertKind::ResumedAfterPanic(generator) => {
|
AssertKind::ResumedAfterPanic(generator) => {
|
||||||
stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator(
|
stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable())
|
||||||
generator,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
AssertKind::MisalignedPointerDereference { required, found } => {
|
AssertKind::MisalignedPointerDereference { required, found } => {
|
||||||
stable_mir::mir::AssertMessage::MisalignedPointerDereference {
|
stable_mir::mir::AssertMessage::MisalignedPointerDereference {
|
||||||
required: rustc_op_to_op(required),
|
required: required.stable(),
|
||||||
found: rustc_op_to_op(found),
|
found: found.stable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp {
|
impl Stable for mir::BinOp {
|
||||||
use rustc_middle::mir::BinOp;
|
type T = stable_mir::mir::BinOp;
|
||||||
match bin_op {
|
fn stable(&self) -> Self::T {
|
||||||
BinOp::Add => stable_mir::mir::BinOp::Add,
|
use mir::BinOp;
|
||||||
BinOp::Sub => stable_mir::mir::BinOp::Sub,
|
match self {
|
||||||
BinOp::Mul => stable_mir::mir::BinOp::Mul,
|
BinOp::Add => stable_mir::mir::BinOp::Add,
|
||||||
BinOp::Div => stable_mir::mir::BinOp::Div,
|
BinOp::Sub => stable_mir::mir::BinOp::Sub,
|
||||||
BinOp::Rem => stable_mir::mir::BinOp::Rem,
|
BinOp::Mul => stable_mir::mir::BinOp::Mul,
|
||||||
BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
|
BinOp::Div => stable_mir::mir::BinOp::Div,
|
||||||
BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
|
BinOp::Rem => stable_mir::mir::BinOp::Rem,
|
||||||
BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
|
BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
|
||||||
BinOp::Shl => stable_mir::mir::BinOp::Shl,
|
BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
|
||||||
BinOp::Shr => stable_mir::mir::BinOp::Shr,
|
BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
|
||||||
BinOp::Eq => stable_mir::mir::BinOp::Eq,
|
BinOp::Shl => stable_mir::mir::BinOp::Shl,
|
||||||
BinOp::Lt => stable_mir::mir::BinOp::Lt,
|
BinOp::Shr => stable_mir::mir::BinOp::Shr,
|
||||||
BinOp::Le => stable_mir::mir::BinOp::Le,
|
BinOp::Eq => stable_mir::mir::BinOp::Eq,
|
||||||
BinOp::Ne => stable_mir::mir::BinOp::Ne,
|
BinOp::Lt => stable_mir::mir::BinOp::Lt,
|
||||||
BinOp::Ge => stable_mir::mir::BinOp::Ge,
|
BinOp::Le => stable_mir::mir::BinOp::Le,
|
||||||
BinOp::Gt => stable_mir::mir::BinOp::Gt,
|
BinOp::Ne => stable_mir::mir::BinOp::Ne,
|
||||||
BinOp::Offset => stable_mir::mir::BinOp::Offset,
|
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 {
|
impl Stable for mir::UnOp {
|
||||||
use rustc_middle::mir::UnOp;
|
type T = stable_mir::mir::UnOp;
|
||||||
match unary_op {
|
fn stable(&self) -> Self::T {
|
||||||
UnOp::Not => stable_mir::mir::UnOp::Not,
|
use mir::UnOp;
|
||||||
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
match self {
|
||||||
|
UnOp::Not => stable_mir::mir::UnOp::Not,
|
||||||
|
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_generator_to_generator(
|
impl Stable for rustc_hir::GeneratorKind {
|
||||||
generator: &rustc_hir::GeneratorKind,
|
type T = stable_mir::mir::GeneratorKind;
|
||||||
) -> stable_mir::mir::GeneratorKind {
|
fn stable(&self) -> Self::T {
|
||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
||||||
match generator {
|
match self {
|
||||||
GeneratorKind::Async(async_gen) => {
|
GeneratorKind::Async(async_gen) => {
|
||||||
let async_gen = match async_gen {
|
let async_gen = match async_gen {
|
||||||
AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
|
AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
|
||||||
AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
|
AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
|
||||||
AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
|
AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
|
||||||
};
|
};
|
||||||
stable_mir::mir::GeneratorKind::Async(async_gen)
|
stable_mir::mir::GeneratorKind::Async(async_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;
|
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
|
|
||||||
stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", operand) }
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
}
|
||||||
|
GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen,
|
||||||
}
|
}
|
||||||
Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
|
}
|
||||||
cond: rustc_op_to_op(cond),
|
}
|
||||||
expected: *expected,
|
|
||||||
msg: rustc_assert_msg_to_msg(msg),
|
impl<'tcx> Stable for mir::InlineAsmOperand<'tcx> {
|
||||||
target: target.as_usize(),
|
type T = stable_mir::mir::InlineAsmOperand;
|
||||||
unwind: rustc_unwind_to_unwind(unwind),
|
fn stable(&self) -> Self::T {
|
||||||
},
|
use rustc_middle::mir::InlineAsmOperand;
|
||||||
InlineAsm { template, operands, options, line_spans, destination, unwind } => {
|
|
||||||
Terminator::InlineAsm {
|
let (in_value, out_place) = match self {
|
||||||
template: format!("{:?}", template),
|
InlineAsmOperand::In { value, .. } => (Some(value.stable()), None),
|
||||||
operands: operands
|
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!("{:?}", self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
.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(),
|
.collect(),
|
||||||
options: format!("{:?}", options),
|
otherwise: targets.otherwise().as_usize(),
|
||||||
line_spans: format!("{:?}", line_spans),
|
},
|
||||||
destination: destination.map(|d| d.as_usize()),
|
Resume => Terminator::Resume,
|
||||||
unwind: rustc_unwind_to_unwind(unwind),
|
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!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use super::{Target, TargetOptions};
|
|||||||
|
|
||||||
pub fn target() -> Target {
|
pub fn target() -> Target {
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "loongarch64-unknown-none-softfloat".into(),
|
llvm_target: "loongarch64-unknown-none".into(),
|
||||||
pointer_width: 64,
|
pointer_width: 64,
|
||||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
|
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
|
||||||
arch: "loongarch64".into(),
|
arch: "loongarch64".into(),
|
||||||
|
@ -23,7 +23,7 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
|
|||||||
use rustc_middle::traits::DefiningAnchor;
|
use rustc_middle::traits::DefiningAnchor;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
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::symbol::sym;
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -170,8 +170,8 @@ fn overlap<'tcx>(
|
|||||||
overlap_mode: OverlapMode,
|
overlap_mode: OverlapMode,
|
||||||
) -> Option<OverlapResult<'tcx>> {
|
) -> Option<OverlapResult<'tcx>> {
|
||||||
if overlap_mode.use_negative_impl() {
|
if overlap_mode.use_negative_impl() {
|
||||||
if negative_impl(tcx, impl1_def_id, impl2_def_id)
|
if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id)
|
||||||
|| negative_impl(tcx, impl2_def_id, impl1_def_id)
|
|| impl_intersection_has_negative_obligation(tcx, impl2_def_id, impl1_def_id)
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -198,13 +198,21 @@ fn overlap<'tcx>(
|
|||||||
let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
|
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 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");
|
debug!("overlap: unification check succeeded");
|
||||||
|
|
||||||
if overlap_mode.use_implicit_negative() {
|
if overlap_mode.use_implicit_negative()
|
||||||
if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
|
&& impl_intersection_has_impossible_obligation(
|
||||||
return None;
|
selcx,
|
||||||
}
|
param_env,
|
||||||
|
&impl1_header,
|
||||||
|
impl2_header,
|
||||||
|
equate_obligations,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We toggle the `leak_check` by using `skip_leak_check` when constructing the
|
// 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()
|
result.map(|infer_ok| infer_ok.obligations).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
|
/// Check if both impls can be satisfied by a common type by considering whether
|
||||||
/// where-clauses) If so, return false, otherwise return true, they are disjoint.
|
/// any of either impl's obligations is not known to hold.
|
||||||
fn implicit_negative<'cx, 'tcx>(
|
///
|
||||||
|
/// For example, given these two impls:
|
||||||
|
/// `impl From<MyLocalType> for Box<dyn Error>` (in my crate)
|
||||||
|
/// `impl<E> From<E> for Box<dyn Error> where E: Error` (in libstd)
|
||||||
|
///
|
||||||
|
/// After replacing both impl headers with inference vars (which happens before
|
||||||
|
/// this function is called), we get:
|
||||||
|
/// `Box<dyn Error>: From<MyLocalType>`
|
||||||
|
/// `Box<dyn Error>: From<?E>`
|
||||||
|
///
|
||||||
|
/// 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>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
impl1_header: &ty::ImplHeader<'tcx>,
|
impl1_header: &ty::ImplHeader<'tcx>,
|
||||||
impl2_header: ty::ImplHeader<'tcx>,
|
impl2_header: ty::ImplHeader<'tcx>,
|
||||||
obligations: PredicateObligations<'tcx>,
|
obligations: PredicateObligations<'tcx>,
|
||||||
) -> bool {
|
) -> 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<dyn Error>`
|
|
||||||
// `impl<E> From<E> for Box<dyn Error> where E: Error`
|
|
||||||
//
|
|
||||||
// So we have:
|
|
||||||
//
|
|
||||||
// `Box<dyn Error>: From<&'?a str>`
|
|
||||||
// `Box<dyn Error>: From<?E>`
|
|
||||||
//
|
|
||||||
// After equating the two headers:
|
|
||||||
//
|
|
||||||
// `Box<dyn Error> = Box<dyn Error>`
|
|
||||||
// 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 infcx = selcx.infcx;
|
||||||
let opt_failing_obligation = impl1_header
|
|
||||||
.predicates
|
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
|
||||||
.iter()
|
.into_iter()
|
||||||
.copied()
|
.flatten()
|
||||||
.chain(impl2_header.predicates)
|
.map(|&predicate| {
|
||||||
.map(|p| infcx.resolve_vars_if_possible(p))
|
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
|
||||||
.map(|p| Obligation {
|
|
||||||
cause: ObligationCause::dummy(),
|
|
||||||
param_env,
|
|
||||||
recursion_depth: 0,
|
|
||||||
predicate: p,
|
|
||||||
})
|
})
|
||||||
.chain(obligations)
|
.chain(obligations)
|
||||||
.find(|o| !selcx.predicate_may_hold_fatal(o));
|
.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
|
/// Check if both impls can be satisfied by a common type by considering whether
|
||||||
/// where-clauses) If so, return true, they are disjoint and false otherwise.
|
/// any of first impl's obligations is known not to hold *via a negative predicate*.
|
||||||
fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> bool {
|
///
|
||||||
|
/// For example, given these two impls:
|
||||||
|
/// `struct MyCustomBox<T: ?Sized>(Box<T>);`
|
||||||
|
/// `impl From<&str> for MyCustomBox<dyn Error>` (in my crate)
|
||||||
|
/// `impl<E> From<E> for MyCustomBox<dyn Error> where E: Error` (in my crate)
|
||||||
|
///
|
||||||
|
/// After replacing the second impl's header with inference vars, we get:
|
||||||
|
/// `MyCustomBox<dyn Error>: From<&str>`
|
||||||
|
/// `MyCustomBox<dyn Error>: From<?E>`
|
||||||
|
///
|
||||||
|
/// 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);
|
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:
|
// 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.
|
// Attempt to prove that impl2 applies, given all of the above.
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
|
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, |_, _| {
|
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| {
|
||||||
ObligationCause::dummy()
|
ObligationCause::dummy()
|
||||||
});
|
});
|
||||||
|
|
||||||
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
|
// 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, .. }) =
|
||||||
fn equate<'tcx>(
|
|
||||||
infcx: &InferCtxt<'tcx>,
|
|
||||||
impl_env: ty::ParamEnv<'tcx>,
|
|
||||||
subject1: ImplSubject<'tcx>,
|
|
||||||
subject2: ImplSubject<'tcx>,
|
|
||||||
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
|
|
||||||
body_def_id: DefId,
|
|
||||||
) -> bool {
|
|
||||||
// do the impls unify? If not, not disjoint.
|
|
||||||
let Ok(InferOk { obligations: more_obligations, .. }) =
|
|
||||||
infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
|
infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
|
||||||
else {
|
else {
|
||||||
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
|
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
|
||||||
return true;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_failing_obligation = obligations
|
for obligation in normalization_obligations.into_iter().chain(equate_obligations) {
|
||||||
.into_iter()
|
if negative_impl_exists(&infcx, &obligation, impl1_def_id) {
|
||||||
.chain(more_obligations)
|
debug!("overlap: obligation unsatisfiable {:?}", obligation);
|
||||||
.find(|o| negative_impl_exists(infcx, o, body_def_id));
|
return true;
|
||||||
|
}
|
||||||
if let Some(failing_obligation) = opt_failing_obligation {
|
|
||||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
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))]
|
#[instrument(level = "debug", skip(infcx))]
|
||||||
fn negative_impl_exists<'tcx>(
|
fn negative_impl_exists<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
o: &PredicateObligation<'tcx>,
|
o: &PredicateObligation<'tcx>,
|
||||||
body_def_id: DefId,
|
body_def_id: DefId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if resolve_negative_obligation(infcx.fork(), o, body_def_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to prove a negative obligation exists for super predicates
|
// Try to prove a negative obligation exists for super predicates
|
||||||
for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,7 +395,7 @@ fn negative_impl_exists<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(infcx))]
|
#[instrument(level = "debug", skip(infcx))]
|
||||||
fn resolve_negative_obligation<'tcx>(
|
fn prove_negated_obligation<'tcx>(
|
||||||
infcx: InferCtxt<'tcx>,
|
infcx: InferCtxt<'tcx>,
|
||||||
o: &PredicateObligation<'tcx>,
|
o: &PredicateObligation<'tcx>,
|
||||||
body_def_id: DefId,
|
body_def_id: DefId,
|
||||||
|
@ -365,7 +365,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !candidate_set.ambiguous && no_candidates_apply {
|
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() {
|
if !trait_ref.references_error() {
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
let (trait_desc, self_desc) = with_no_trimmed_paths!({
|
let (trait_desc, self_desc) = with_no_trimmed_paths!({
|
||||||
|
@ -22,7 +22,7 @@ where
|
|||||||
Successors { next: first, succ }
|
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.
|
/// This `struct` is created by the [`iter::successors()`] function.
|
||||||
/// See its documentation for more.
|
/// See its documentation for more.
|
||||||
|
@ -1 +1 @@
|
|||||||
0.16.6
|
0.16.7
|
@ -201,8 +201,8 @@ async function main(argv) {
|
|||||||
try {
|
try {
|
||||||
// This is more convenient that setting fields one by one.
|
// This is more convenient that setting fields one by one.
|
||||||
const args = [
|
const args = [
|
||||||
"--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error",
|
"--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
|
||||||
"--allow-file-access-from-files",
|
"--enable-fail-on-js-error", "--allow-file-access-from-files",
|
||||||
];
|
];
|
||||||
if (opts["debug"]) {
|
if (opts["debug"]) {
|
||||||
debug = true;
|
debug = true;
|
||||||
|
@ -13,7 +13,7 @@ press-key: "Escape"
|
|||||||
assert-css: ("#help-button .popover", {"display": "none"})
|
assert-css: ("#help-button .popover", {"display": "none"})
|
||||||
// Checking doc collapse and expand.
|
// Checking doc collapse and expand.
|
||||||
// It should be displaying a "-":
|
// It should be displaying a "-":
|
||||||
assert-text: ("#toggle-all-docs", "[\u2212]")
|
assert-text: ("#toggle-all-docs", "[−]")
|
||||||
press-key: "-"
|
press-key: "-"
|
||||||
wait-for-text: ("#toggle-all-docs", "[+]")
|
wait-for-text: ("#toggle-all-docs", "[+]")
|
||||||
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
|
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"})
|
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
|
||||||
// Expanding now.
|
// Expanding now.
|
||||||
press-key: "+"
|
press-key: "+"
|
||||||
wait-for-text: ("#toggle-all-docs", "[\u2212]")
|
wait-for-text: ("#toggle-all-docs", "[−]")
|
||||||
assert-attribute: ("#toggle-all-docs", {"class": ""})
|
assert-attribute: ("#toggle-all-docs", {"class": ""})
|
||||||
// Pressing it again shouldn't do anything.
|
// Pressing it again shouldn't do anything.
|
||||||
press-key: "+"
|
press-key: "+"
|
||||||
assert-text: ("#toggle-all-docs", "[\u2212]")
|
assert-text: ("#toggle-all-docs", "[−]")
|
||||||
assert-attribute: ("#toggle-all-docs", {"class": ""})
|
assert-attribute: ("#toggle-all-docs", {"class": ""})
|
||||||
|
@ -64,23 +64,23 @@ call-function: ("check-colors", {
|
|||||||
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
|
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
|
||||||
// Check the `href` property so that users can treat anchors as links.
|
// Check the `href` property so that users can treat anchors as links.
|
||||||
assert-property: (".src-line-numbers > a:nth-child(1)", {
|
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)", {
|
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)", {
|
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)", {
|
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)", {
|
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)", {
|
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 that the line numbers text is aligned to the right.
|
||||||
assert-css: (".src-line-numbers", {"text-align": "right"})
|
assert-css: (".src-line-numbers", {"text-align": "right"})
|
||||||
|
@ -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`.
|
@ -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`.
|
@ -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`.
|
@ -1,51 +1,62 @@
|
|||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
// revisions: mismatch mismatch_async too_many too_few lt
|
||||||
|
|
||||||
#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
|
#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
#[cfg(mismatch)]
|
||||||
trait Uwu {
|
trait Uwu {
|
||||||
fn owo(x: ()) -> impl Sized;
|
fn owo(x: ()) -> impl Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(mismatch)]
|
||||||
impl Uwu for () {
|
impl Uwu for () {
|
||||||
fn owo(_: u8) {}
|
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 {
|
trait AsyncUwu {
|
||||||
async fn owo(x: ()) {}
|
async fn owo(x: ()) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(mismatch_async)]
|
||||||
impl AsyncUwu for () {
|
impl AsyncUwu for () {
|
||||||
async fn owo(_: u8) {}
|
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 {
|
trait TooMuch {
|
||||||
fn calm_down_please() -> impl Sized;
|
fn calm_down_please() -> impl Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(too_many)]
|
||||||
impl TooMuch for () {
|
impl TooMuch for () {
|
||||||
fn calm_down_please(_: (), _: (), _: ()) {}
|
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 {
|
trait TooLittle {
|
||||||
fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
|
fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(too_few)]
|
||||||
impl TooLittle for () {
|
impl TooLittle for () {
|
||||||
fn come_on_a_little_more_effort() {}
|
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 {
|
trait Lifetimes {
|
||||||
fn early<'early, T>(x: &'early T) -> impl Sized;
|
fn early<'early, T>(x: &'early T) -> impl Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(lt)]
|
||||||
impl Lifetimes for () {
|
impl Lifetimes for () {
|
||||||
fn early<'late, T>(_: &'late ()) {}
|
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() {}
|
fn main() {}
|
||||||
|
@ -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`.
|
|
@ -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`.
|
@ -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`.
|
@ -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`.
|
@ -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`.
|
16
tests/ui/impl-trait/in-trait/unconstrained-lt.rs
Normal file
16
tests/ui/impl-trait/in-trait/unconstrained-lt.rs
Normal file
@ -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() {}
|
@ -801,4 +801,10 @@ where
|
|||||||
yoo: &'a U
|
yoo: &'a U
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/rust-lang/rust/issues/105150
|
||||||
|
struct InferredWhereBoundWithInlineBound<'a, T: ?Sized>
|
||||||
|
{
|
||||||
|
data: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -801,4 +801,12 @@ where
|
|||||||
yoo: &'a U
|
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() {}
|
fn main() {}
|
||||||
|
@ -10,6 +10,15 @@ note: the lint level is defined here
|
|||||||
LL | #![deny(explicit_outlives_requirements)]
|
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
|
error: outlives requirements can be inferred
|
||||||
--> $DIR/edition-lint-infer-outlives.rs:26:31
|
--> $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 {
|
LL | union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug {
|
||||||
| ^^^^^^^^ help: remove this bound
|
| ^^^^^^^^ help: remove this bound
|
||||||
|
|
||||||
error: aborting due to 153 previous errors
|
error: aborting due to 154 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user