Auto merge of #111869 - Dylan-DPC:rollup-9pydw08, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #111461 (Fix symbol conflict diagnostic mistakenly being shown instead of missing crate diagnostic) - #111579 (Also assume wrap-around discriminants in `as` MIR building) - #111704 (Remove return type sized check hack from hir typeck) - #111853 (Check opaques for mismatch during writeback) - #111854 (rustdoc: clean up `settings.css`) - #111860 (Don't ICE if method receiver fails to unify with `arbitrary_self_types`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b08148f6a7
@ -152,8 +152,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
||||
prev.report_mismatch(
|
||||
&OpaqueHiddenType { ty, span: concrete_type.span },
|
||||
opaque_type_key.def_id,
|
||||
infcx.tcx,
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
prev.ty = infcx.tcx.ty_error(guar);
|
||||
}
|
||||
|
@ -478,6 +478,7 @@ pub enum StashKey {
|
||||
MaybeFruTypo,
|
||||
CallAssocMethod,
|
||||
TraitMissingMethod,
|
||||
OpaqueHiddenTypeMismatch,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
|
||||
|
@ -584,7 +584,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
|
||||
debug!(?concrete_type, "found constraint");
|
||||
if let Some(prev) = &mut self.found {
|
||||
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
|
||||
let guar = prev.report_mismatch(&concrete_type, self.tcx);
|
||||
let guar =
|
||||
prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
|
||||
prev.ty = self.tcx.ty_error(guar);
|
||||
}
|
||||
} else {
|
||||
@ -678,10 +679,10 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
|
||||
// Only check against typeck if we didn't already error
|
||||
if !hidden.ty.references_error() {
|
||||
for concrete_type in locator.typeck_types {
|
||||
if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
|
||||
if concrete_type.ty != tcx.erase_regions(hidden.ty)
|
||||
&& !(concrete_type, hidden).references_error()
|
||||
{
|
||||
hidden.report_mismatch(&concrete_type, tcx);
|
||||
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -722,7 +723,7 @@ fn find_opaque_ty_constraints_for_rpit(
|
||||
if concrete_type.ty != self.found.ty
|
||||
&& !(concrete_type, self.found).references_error()
|
||||
{
|
||||
self.found.report_mismatch(&concrete_type, self.tcx);
|
||||
self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,24 +103,8 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
|
||||
fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
|
||||
|
||||
if let ty::Dynamic(_, _, ty::Dyn) = declared_ret_ty.kind() {
|
||||
// FIXME: We need to verify that the return type is `Sized` after the return expression has
|
||||
// been evaluated so that we have types available for all the nodes being returned, but that
|
||||
// requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
|
||||
// causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
|
||||
// while keeping the current ordering we will ignore the tail expression's type because we
|
||||
// don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
|
||||
// because we will trigger "unreachable expression" lints unconditionally.
|
||||
// Because of all of this, we perform a crude check to know whether the simplest `!Sized`
|
||||
// case that a newcomer might make, returning a bare trait, and in that case we populate
|
||||
// the tail expression's type so that the suggestion will be correct, but ignore all other
|
||||
// possible cases.
|
||||
fcx.check_expr(&body.value);
|
||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||
} else {
|
||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||
fcx.check_return_expr(&body.value, false);
|
||||
}
|
||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||
fcx.check_return_expr(&body.value, false);
|
||||
|
||||
// We insert the deferred_generator_interiors entry after visiting the body.
|
||||
// This ensures that all nested generators appear before the entry of this generator.
|
||||
|
@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
self_ty, method_self_ty, self.span, pick
|
||||
);
|
||||
let cause = self.cause(
|
||||
self.span,
|
||||
self.self_expr.span,
|
||||
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
|
||||
assoc_item: pick.item,
|
||||
param_env: self.param_env,
|
||||
@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
}
|
||||
Err(_) => {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"{} was a subtype of {} but now is not?",
|
||||
self_ty,
|
||||
method_self_ty
|
||||
);
|
||||
Err(terr) => {
|
||||
// FIXME(arbitrary_self_types): We probably should limit the
|
||||
// situations where this can occur by adding additional restrictions
|
||||
// to the feature, like the self type can't reference method substs.
|
||||
if self.tcx.features().arbitrary_self_types {
|
||||
self.err_ctxt()
|
||||
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
|
||||
.emit();
|
||||
} else {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"{} was a subtype of {} but now is not?",
|
||||
self_ty,
|
||||
method_self_ty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::FnCtxt;
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
@ -82,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
wbcx.typeck_results.treat_byte_string_as_slice =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
|
||||
|
||||
if let Some(e) = self.tainted_by_errors() {
|
||||
wbcx.typeck_results.tainted_by_errors = Some(e);
|
||||
}
|
||||
|
||||
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
|
||||
|
||||
self.tcx.arena.alloc(wbcx.typeck_results)
|
||||
@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
) -> WritebackCx<'cx, 'tcx> {
|
||||
let owner = body.id().hir_id.owner;
|
||||
|
||||
WritebackCx {
|
||||
let mut wbcx = WritebackCx {
|
||||
fcx,
|
||||
typeck_results: ty::TypeckResults::new(owner),
|
||||
body,
|
||||
rustc_dump_user_substs,
|
||||
};
|
||||
|
||||
// HACK: We specifically don't want the (opaque) error from tainting our
|
||||
// inference context. That'll prevent us from doing opaque type inference
|
||||
// later on in borrowck, which affects diagnostic spans pretty negatively.
|
||||
if let Some(e) = fcx.tainted_by_errors() {
|
||||
wbcx.typeck_results.tainted_by_errors = Some(e);
|
||||
}
|
||||
|
||||
wbcx
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
|
||||
opaque_type_key,
|
||||
self.fcx.infcx.tcx,
|
||||
true,
|
||||
);
|
||||
let hidden_type =
|
||||
self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
|
||||
opaque_type_key,
|
||||
self.tcx(),
|
||||
true,
|
||||
));
|
||||
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
|
||||
if let Some(last_opaque_ty) = self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.insert(opaque_type_key.def_id, hidden_type)
|
||||
&& last_opaque_ty.ty != hidden_type.ty
|
||||
{
|
||||
hidden_type
|
||||
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
|
||||
.stash(
|
||||
self.tcx().def_span(opaque_type_key.def_id),
|
||||
StashKey::OpaqueHiddenTypeMismatch,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,15 @@ impl CStore {
|
||||
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
|
||||
let num = CrateNum::new(self.stable_crate_ids.len());
|
||||
if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
|
||||
let crate_name0 = root.name();
|
||||
if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) {
|
||||
// Check for (potential) conflicts with the local crate
|
||||
if existing == LOCAL_CRATE {
|
||||
Err(CrateError::SymbolConflictsCurrent(root.name()))
|
||||
} else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
|
||||
{
|
||||
let crate_name0 = root.name();
|
||||
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
|
||||
} else {
|
||||
Err(CrateError::SymbolConflictsCurrent(crate_name0))
|
||||
Err(CrateError::NotFound(root.name()))
|
||||
}
|
||||
} else {
|
||||
self.metas.push(None);
|
||||
|
@ -961,6 +961,7 @@ pub(crate) enum CrateError {
|
||||
DlSym(String),
|
||||
LocatorCombined(Box<CombinedLocatorError>),
|
||||
NonDylibPlugin(Symbol),
|
||||
NotFound(Symbol),
|
||||
}
|
||||
|
||||
enum MetadataError<'a> {
|
||||
@ -1131,6 +1132,18 @@ impl CrateError {
|
||||
CrateError::NonDylibPlugin(crate_name) => {
|
||||
sess.emit_err(errors::NoDylibPlugin { span, crate_name });
|
||||
}
|
||||
CrateError::NotFound(crate_name) => {
|
||||
sess.emit_err(errors::CannotFindCrate {
|
||||
span,
|
||||
crate_name,
|
||||
add_info: String::new(),
|
||||
missing_core,
|
||||
current_crate: sess.opts.crate_name.clone().unwrap_or("<unknown>".to_string()),
|
||||
is_nightly_build: sess.is_nightly_build(),
|
||||
profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
|
||||
locator_triple: sess.opts.target_triple.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
@ -1439,14 +1439,26 @@ pub struct OpaqueHiddenType<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueHiddenType<'tcx> {
|
||||
pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed {
|
||||
pub fn report_mismatch(
|
||||
&self,
|
||||
other: &Self,
|
||||
opaque_def_id: LocalDefId,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
if let Some(diag) = tcx
|
||||
.sess
|
||||
.diagnostic()
|
||||
.steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
|
||||
{
|
||||
diag.cancel();
|
||||
}
|
||||
// Found different concrete types for the opaque type.
|
||||
let sub_diag = if self.span == other.span {
|
||||
TypeMismatchReason::ConflictType { span: self.span }
|
||||
} else {
|
||||
TypeMismatchReason::PreviousUse { span: self.span }
|
||||
};
|
||||
tcx.sess.emit_err(OpaqueHiddenTypeMismatch {
|
||||
tcx.sess.create_err(OpaqueHiddenTypeMismatch {
|
||||
self_ty: self.ty,
|
||||
other_ty: other.ty,
|
||||
other_span: other.span,
|
||||
|
@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> {
|
||||
/// this field will be set to `Some(ErrorGuaranteed)`.
|
||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
|
||||
/// All the opaque types that have hidden types set
|
||||
/// by this function. We also store the
|
||||
/// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
|
||||
/// even if they are only set in dead code (which doesn't show up in MIR).
|
||||
/// All the opaque types that have hidden types set by this function.
|
||||
/// We also store the type here, so that the compiler can use it as a hint
|
||||
/// for figuring out hidden types, even if they are only set in dead code
|
||||
/// (which doesn't show up in MIR).
|
||||
///
|
||||
/// These types are mapped back to the opaque's identity substitutions
|
||||
/// (with erased regions), which is why we don't associated substs with any
|
||||
/// of these usages.
|
||||
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||
|
||||
/// Tracks the minimum captures required for a closure;
|
||||
|
@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, Ty, UpvarSubsts};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
);
|
||||
let (op,ty) = (Operand::Move(discr), discr_ty);
|
||||
|
||||
if let Abi::Scalar(scalar) = layout.unwrap().abi{
|
||||
if let Primitive::Int(_, signed) = scalar.primitive() {
|
||||
let range = scalar.valid_range(&this.tcx);
|
||||
// FIXME: Handle wraparound cases too.
|
||||
if range.end >= range.start {
|
||||
let mut assumer = |range: u128, bin_op: BinOp| {
|
||||
// We will be overwriting this val if our scalar is signed value
|
||||
// because sign extension on unsigned types might cause unintended things
|
||||
let mut range_val =
|
||||
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
|
||||
let bool_ty = this.tcx.types.bool;
|
||||
if signed {
|
||||
let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
|
||||
let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
|
||||
let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
|
||||
range_val = ConstantKind::from_bits(
|
||||
this.tcx,
|
||||
truncated_val,
|
||||
ty::ParamEnv::empty().and(discr_ty),
|
||||
);
|
||||
}
|
||||
let lit_op = this.literal_operand(expr.span, range_val);
|
||||
let is_bin_op = this.temp(bool_ty, expr_span);
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
is_bin_op,
|
||||
Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
|
||||
);
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
|
||||
Operand::Copy(is_bin_op),
|
||||
))),
|
||||
},
|
||||
)
|
||||
};
|
||||
assumer(range.end, BinOp::Ge);
|
||||
assumer(range.start, BinOp::Le);
|
||||
}
|
||||
}
|
||||
if let Abi::Scalar(scalar) = layout.unwrap().abi
|
||||
&& !scalar.is_always_valid(&this.tcx)
|
||||
&& let Primitive::Int(int_width, _signed) = scalar.primitive()
|
||||
{
|
||||
let unsigned_ty = int_width.to_ty(this.tcx, false);
|
||||
let unsigned_place = this.temp(unsigned_ty, expr_span);
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
unsigned_place,
|
||||
Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
|
||||
|
||||
let bool_ty = this.tcx.types.bool;
|
||||
let range = scalar.valid_range(&this.tcx);
|
||||
let merge_op =
|
||||
if range.start <= range.end {
|
||||
BinOp::BitAnd
|
||||
} else {
|
||||
BinOp::BitOr
|
||||
};
|
||||
|
||||
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
|
||||
let range_val =
|
||||
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
|
||||
let lit_op = this.literal_operand(expr.span, range_val);
|
||||
let is_bin_op = this.temp(bool_ty, expr_span);
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
is_bin_op,
|
||||
Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))),
|
||||
);
|
||||
is_bin_op
|
||||
};
|
||||
let assert_place = if range.start == 0 {
|
||||
comparer(range.end, BinOp::Le)
|
||||
} else {
|
||||
let start_place = comparer(range.start, BinOp::Ge);
|
||||
let end_place = comparer(range.end, BinOp::Le);
|
||||
let merge_place = this.temp(bool_ty, expr_span);
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
merge_place,
|
||||
Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))),
|
||||
);
|
||||
merge_place
|
||||
};
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
|
||||
Operand::Move(assert_place),
|
||||
))),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
(op,ty)
|
||||
|
@ -885,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
|
||||
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ use rustc_middle::hir::map;
|
||||
use rustc_middle::ty::error::TypeError::{self, Sorts};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
|
||||
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
|
||||
IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
|
||||
TypeSuperFoldable, TypeVisitableExt, TypeckResults,
|
||||
GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable,
|
||||
ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
TypeVisitableExt, TypeckResults,
|
||||
};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
@ -261,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn suggest_impl_trait(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
@ -1792,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn suggest_impl_trait(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
match obligation.cause.code().peel_derives() {
|
||||
// Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
|
||||
ObligationCauseCode::SizedReturnType => {}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
let hir = self.tcx.hir();
|
||||
let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id);
|
||||
let node = hir.find_by_def_id(obligation.cause.body_id);
|
||||
let Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(sig, _, body_id),
|
||||
..
|
||||
})) = node
|
||||
else {
|
||||
let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
|
||||
return false;
|
||||
};
|
||||
let body = hir.body(*body_id);
|
||||
let trait_pred = self.resolve_vars_if_possible(trait_pred);
|
||||
let ty = trait_pred.skip_binder().self_ty();
|
||||
let is_object_safe = match ty.kind() {
|
||||
ty::Dynamic(predicates, _, ty::Dyn) => {
|
||||
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
|
||||
predicates
|
||||
.principal_def_id()
|
||||
.map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
|
||||
}
|
||||
// We only want to suggest `impl Trait` to `dyn Trait`s.
|
||||
// For example, `fn foo() -> str` needs to be filtered out.
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
|
||||
let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
|
||||
// cases like `fn foo() -> (dyn Trait, i32) {}`.
|
||||
// Recursively look for `TraitObject` types and if there's only one, use that span to
|
||||
// suggest `impl Trait`.
|
||||
|
||||
// Visit to make sure there's a single `return` type to suggest `impl Trait`,
|
||||
// otherwise suggest using `Box<dyn Trait>` or an enum.
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(&body);
|
||||
|
||||
let typeck_results = self.typeck_results.as_ref().unwrap();
|
||||
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
|
||||
|
||||
let ret_types = visitor
|
||||
.returns
|
||||
.iter()
|
||||
.filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
|
||||
.map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
|
||||
let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
|
||||
(None, true, true),
|
||||
|(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
|
||||
(_, ty)| {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
same &=
|
||||
!matches!(ty.kind(), ty::Error(_))
|
||||
&& last_ty.map_or(true, |last_ty| {
|
||||
// FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
|
||||
// *after* in the dependency graph.
|
||||
match (ty.kind(), last_ty.kind()) {
|
||||
(Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_)))
|
||||
| (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_)))
|
||||
| (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_)))
|
||||
| (
|
||||
Infer(InferTy::FreshFloatTy(_)),
|
||||
Infer(InferTy::FreshFloatTy(_)),
|
||||
) => true,
|
||||
_ => ty == last_ty,
|
||||
}
|
||||
});
|
||||
(Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
|
||||
},
|
||||
);
|
||||
let mut spans_and_needs_box = vec![];
|
||||
|
||||
match liberated_sig.output().kind() {
|
||||
ty::Dynamic(predicates, _, ty::Dyn) => {
|
||||
let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id);
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
|
||||
if !only_never_return {
|
||||
for (expr_span, return_ty) in ret_types {
|
||||
let self_ty_satisfies_dyn_predicates = |self_ty| {
|
||||
predicates.iter().all(|predicate| {
|
||||
let pred = predicate.with_self_ty(self.tcx, self_ty);
|
||||
let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred);
|
||||
self.predicate_may_hold(&obl)
|
||||
})
|
||||
};
|
||||
|
||||
if let ty::Adt(def, substs) = return_ty.kind()
|
||||
&& def.is_box()
|
||||
&& self_ty_satisfies_dyn_predicates(substs.type_at(0))
|
||||
{
|
||||
spans_and_needs_box.push((expr_span, false));
|
||||
} else if self_ty_satisfies_dyn_predicates(return_ty) {
|
||||
spans_and_needs_box.push((expr_span, true));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let sm = self.tcx.sess.source_map();
|
||||
if !ret_ty.span.overlaps(span) {
|
||||
return false;
|
||||
}
|
||||
let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
|
||||
if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
|
||||
snippet
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
|
||||
let name = liberated_sig.output().to_string();
|
||||
let name =
|
||||
name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
|
||||
if !name.starts_with("dyn ") {
|
||||
return false;
|
||||
}
|
||||
name.to_owned()
|
||||
};
|
||||
|
||||
err.code(error_code!(E0746));
|
||||
err.set_primary_message("return type cannot have an unboxed trait object");
|
||||
err.children.clear();
|
||||
let impl_trait_msg = "for information on `impl Trait`, see \
|
||||
<https://doc.rust-lang.org/book/ch10-02-traits.html\
|
||||
#returning-types-that-implement-traits>";
|
||||
let trait_obj_msg = "for information on trait objects, see \
|
||||
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
|
||||
#using-trait-objects-that-allow-for-values-of-different-types>";
|
||||
|
||||
let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
|
||||
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
|
||||
if only_never_return {
|
||||
// No return paths, probably using `panic!()` or similar.
|
||||
// Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
|
||||
suggest_trait_object_return_type_alternatives(
|
||||
err,
|
||||
ret_ty.span,
|
||||
trait_obj,
|
||||
is_object_safe,
|
||||
);
|
||||
} else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) {
|
||||
// Suggest `-> impl Trait`.
|
||||
let span = obligation.cause.span;
|
||||
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snip.starts_with("dyn ")
|
||||
{
|
||||
err.span_suggestion(
|
||||
ret_ty.span,
|
||||
format!(
|
||||
"use `impl {1}` as the return type, as all return paths are of type `{}`, \
|
||||
which implements `{1}`",
|
||||
last_ty, trait_obj,
|
||||
),
|
||||
format!("impl {}", trait_obj),
|
||||
Applicability::MachineApplicable,
|
||||
span.with_hi(span.lo() + BytePos(4)),
|
||||
"return an `impl Trait` instead of a `dyn Trait`, \
|
||||
if all returned values are the same type",
|
||||
"impl ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.note(impl_trait_msg);
|
||||
} else {
|
||||
if is_object_safe {
|
||||
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
|
||||
err.multipart_suggestion(
|
||||
"return a boxed trait object instead",
|
||||
vec![
|
||||
(ret_ty.span.shrink_to_lo(), "Box<".to_string()),
|
||||
(span.shrink_to_hi(), ">".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
for (span, needs_box) in spans_and_needs_box {
|
||||
if needs_box {
|
||||
err.multipart_suggestion(
|
||||
"... and box this value",
|
||||
vec![
|
||||
(span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is currently not possible to trigger because E0038 takes precedence, but
|
||||
// leave it in for completeness in case anything changes in an earlier stage.
|
||||
err.note(format!(
|
||||
"if trait `{}` were object-safe, you could return a trait object",
|
||||
trait_obj,
|
||||
));
|
||||
}
|
||||
err.note(trait_obj_msg);
|
||||
err.note(format!(
|
||||
"if all the returned values were of the same type you could use `impl {}` as the \
|
||||
return type",
|
||||
trait_obj,
|
||||
));
|
||||
err.note(impl_trait_msg);
|
||||
err.note("you can create a new `enum` with a variant for each returned type");
|
||||
}
|
||||
|
||||
let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
|
||||
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(&body);
|
||||
|
||||
let mut sugg =
|
||||
vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
|
||||
sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
|
||||
let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
|
||||
if !span.can_be_used_for_suggestions() {
|
||||
vec![]
|
||||
} else if let hir::ExprKind::Call(path, ..) = expr.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind
|
||||
&& method.ident.name == sym::new
|
||||
&& let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind
|
||||
&& box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box())
|
||||
{
|
||||
// Don't box `Box::new`
|
||||
vec![]
|
||||
} else {
|
||||
vec![
|
||||
(span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
err.multipart_suggestion(
|
||||
"box the return type, and wrap all of the returned values in `Box::new`",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@ -4139,37 +3989,6 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_trait_object_return_type_alternatives(
|
||||
err: &mut Diagnostic,
|
||||
ret_ty: Span,
|
||||
trait_obj: &str,
|
||||
is_object_safe: bool,
|
||||
) {
|
||||
err.span_suggestion(
|
||||
ret_ty,
|
||||
format!(
|
||||
"use `impl {}` as the return type if all return paths have the same type but you \
|
||||
want to expose only the trait in the signature",
|
||||
trait_obj,
|
||||
),
|
||||
format!("impl {}", trait_obj),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if is_object_safe {
|
||||
err.multipart_suggestion(
|
||||
format!(
|
||||
"use a boxed trait object if all return paths implement trait `{}`",
|
||||
trait_obj,
|
||||
),
|
||||
vec![
|
||||
(ret_ty.shrink_to_lo(), "Box<".to_string()),
|
||||
(ret_ty.shrink_to_hi(), ">".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect the spans that we see the generic param `param_did`
|
||||
struct ReplaceImplTraitVisitor<'a> {
|
||||
ty_spans: &'a mut Vec<Span>,
|
||||
|
@ -1,6 +1,5 @@
|
||||
.setting-line {
|
||||
margin: 1.2em 0.6em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.setting-radio input, .setting-check input {
|
||||
@ -15,11 +14,6 @@
|
||||
.setting-radio input {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.setting-check input:checked {
|
||||
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
|
||||
<path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
|
||||
<path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
|
||||
}
|
||||
|
||||
.setting-radio span, .setting-check span {
|
||||
padding-bottom: 1px;
|
||||
@ -52,6 +46,9 @@
|
||||
.setting-check input:checked {
|
||||
background-color: var(--settings-input-color);
|
||||
border-width: 1px;
|
||||
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
|
||||
<path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
|
||||
<path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
|
||||
}
|
||||
.setting-radio input:focus, .setting-check input:focus {
|
||||
box-shadow: 0 0 1px 1px var(--settings-input-color);
|
||||
|
28
tests/assembly/option-nonzero-eq.rs
Normal file
28
tests/assembly/option-nonzero-eq.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// revisions: WIN LIN
|
||||
// [WIN] only-windows
|
||||
// [LIN] only-linux
|
||||
// assembly-output: emit-asm
|
||||
// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||
// only-x86_64
|
||||
// ignore-sgx
|
||||
// ignore-debug
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
// CHECK-lABEL: ordering_eq:
|
||||
#[no_mangle]
|
||||
pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
|
||||
// Linux (System V): first two arguments are rdi then rsi
|
||||
// Windows: first two arguments are rcx then rdx
|
||||
// Both use rax for the return value.
|
||||
|
||||
// CHECK-NOT: mov
|
||||
// CHECK-NOT: test
|
||||
// CHECK-NOT: cmp
|
||||
|
||||
// LIN: cmp dil, sil
|
||||
// WIN: cmp cl, dl
|
||||
// CHECK-NEXT: sete al
|
||||
// CHECK-NEXT: ret
|
||||
l == r
|
||||
}
|
@ -7,6 +7,9 @@ use core::cmp::Ordering;
|
||||
use core::num::{NonZeroU32, NonZeroI64};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
// See also tests/assembly/option-nonzero-eq.rs, for cases with `assume`s in the
|
||||
// LLVM and thus don't optimize down clearly here, but do in assembly.
|
||||
|
||||
// CHECK-lABEL: @non_zero_eq
|
||||
#[no_mangle]
|
||||
pub fn non_zero_eq(l: Option<NonZeroU32>, r: Option<NonZeroU32>) -> bool {
|
||||
@ -33,12 +36,3 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
|
||||
// CHECK-NEXT: ret i1
|
||||
l == r
|
||||
}
|
||||
|
||||
// CHECK-lABEL: @ordering_eq
|
||||
#[no_mangle]
|
||||
pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: icmp eq i8
|
||||
// CHECK-NEXT: ret i1
|
||||
l == r
|
||||
}
|
||||
|
@ -5,17 +5,16 @@ fn bar(_1: Bar) -> usize {
|
||||
let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
|
||||
let _2: Bar; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_4 = Ge(const 1_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_5 = Le(const 0_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
|
||||
|
@ -5,17 +5,16 @@ fn boo(_1: Boo) -> usize {
|
||||
let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
|
||||
let _2: Boo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _3: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_4 = Ge(const 1_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_5 = Le(const 0_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
|
||||
|
@ -6,7 +6,7 @@ fn droppy() -> () {
|
||||
let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
|
||||
let _4: Droppy; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
|
||||
let mut _5: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
|
||||
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
let mut _6: u8; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
let _8: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
|
||||
scope 1 {
|
||||
@ -31,10 +31,9 @@ fn droppy() -> () {
|
||||
StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
|
||||
_4 = move _2; // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
|
||||
_5 = discriminant(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
_6 = Ge(const 2_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
assume(_6); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
_7 = Le(const 0_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
assume(_7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
_6 = _5 as u8 (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
_7 = Le(_6, const 2_u8); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
assume(move _7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
_3 = move _5 as usize (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||
drop(_4) -> [return: bb1, unwind: bb4]; // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
|
||||
}
|
||||
|
22
tests/mir-opt/building/enum_cast.far.built.after.mir
Normal file
22
tests/mir-opt/building/enum_cast.far.built.after.mir
Normal file
@ -0,0 +1,22 @@
|
||||
// MIR for `far` after built
|
||||
|
||||
fn far(_1: Far) -> isize {
|
||||
debug far => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
|
||||
let mut _0: isize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
|
||||
let _2: Far; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_5 = Le(_4, const 1_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
_0 = move _3 as isize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
|
||||
}
|
||||
}
|
26
tests/mir-opt/building/enum_cast.offsetty.built.after.mir
Normal file
26
tests/mir-opt/building/enum_cast.offsetty.built.after.mir
Normal file
@ -0,0 +1,26 @@
|
||||
// MIR for `offsetty` after built
|
||||
|
||||
fn offsetty(_1: NotStartingAtZero) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:13: +0:14
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41
|
||||
let _2: NotStartingAtZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_5 = Ge(_4, const 4_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_6 = Le(_4, const 8_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_7 = BitAnd(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_0 = move _3 as u32 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// EMIT_MIR enum_cast.foo.built.after.mir
|
||||
// EMIT_MIR enum_cast.bar.built.after.mir
|
||||
// EMIT_MIR enum_cast.boo.built.after.mir
|
||||
// EMIT_MIR enum_cast.far.built.after.mir
|
||||
|
||||
enum Foo {
|
||||
A
|
||||
@ -15,6 +16,11 @@ enum Boo {
|
||||
A, B
|
||||
}
|
||||
|
||||
#[repr(i16)]
|
||||
enum Far {
|
||||
A, B
|
||||
}
|
||||
|
||||
fn foo(foo: Foo) -> usize {
|
||||
foo as usize
|
||||
}
|
||||
@ -27,6 +33,10 @@ fn boo(boo: Boo) -> usize {
|
||||
boo as usize
|
||||
}
|
||||
|
||||
fn far(far: Far) -> isize {
|
||||
far as isize
|
||||
}
|
||||
|
||||
// EMIT_MIR enum_cast.droppy.built.after.mir
|
||||
enum Droppy {
|
||||
A, B, C
|
||||
@ -46,5 +56,37 @@ fn droppy() {
|
||||
let z = Droppy::B;
|
||||
}
|
||||
|
||||
#[repr(i16)]
|
||||
enum SignedAroundZero {
|
||||
A = -2,
|
||||
B = 0,
|
||||
C = 2,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
enum UnsignedAroundZero {
|
||||
A = 65535,
|
||||
B = 0,
|
||||
C = 1,
|
||||
}
|
||||
|
||||
// EMIT_MIR enum_cast.signy.built.after.mir
|
||||
fn signy(x: SignedAroundZero) -> i16 {
|
||||
x as i16
|
||||
}
|
||||
|
||||
// EMIT_MIR enum_cast.unsigny.built.after.mir
|
||||
fn unsigny(x: UnsignedAroundZero) -> u16 {
|
||||
// FIXME: This doesn't get an around-the-end range today, sadly.
|
||||
x as u16
|
||||
}
|
||||
|
||||
enum NotStartingAtZero { A = 4, B = 6, C = 8 }
|
||||
|
||||
// EMIT_MIR enum_cast.offsetty.built.after.mir
|
||||
fn offsetty(x: NotStartingAtZero) -> u32 {
|
||||
x as u32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
26
tests/mir-opt/building/enum_cast.signy.built.after.mir
Normal file
26
tests/mir-opt/building/enum_cast.signy.built.after.mir
Normal file
@ -0,0 +1,26 @@
|
||||
// MIR for `signy` after built
|
||||
|
||||
fn signy(_1: SignedAroundZero) -> i16 {
|
||||
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:10: +0:11
|
||||
let mut _0: i16; // return place in scope 0 at $DIR/enum_cast.rs:+0:34: +0:37
|
||||
let _2: SignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_5 = Ge(_4, const 65534_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_6 = Le(_4, const 2_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_7 = BitOr(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
_0 = move _3 as i16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
|
||||
}
|
||||
}
|
17
tests/mir-opt/building/enum_cast.unsigny.built.after.mir
Normal file
17
tests/mir-opt/building/enum_cast.unsigny.built.after.mir
Normal file
@ -0,0 +1,17 @@
|
||||
// MIR for `unsigny` after built
|
||||
|
||||
fn unsigny(_1: UnsignedAroundZero) -> u16 {
|
||||
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:12: +0:13
|
||||
let mut _0: u16; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41
|
||||
let _2: UnsignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
|
||||
let mut _3: u16; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
|
||||
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13
|
||||
_0 = move _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13
|
||||
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+2:12: +2:13
|
||||
return; // scope 0 at $DIR/enum_cast.rs:+3:2: +3:2
|
||||
}
|
||||
}
|
@ -29,5 +29,5 @@ all:
|
||||
--crate-type=rlib \
|
||||
--edition=2018 \
|
||||
c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
|
||||
$(CGREP) E0519 < $(TMPDIR)/output.txt
|
||||
$(CGREP) E0463 < $(TMPDIR)/output.txt
|
||||
$(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt
|
||||
|
@ -301,7 +301,7 @@ wait-for-css: ("#help-button .popover", {"display": "block"})
|
||||
// Now we go to the settings page to check that the CSS is loaded as expected.
|
||||
go-to: "file://" + |DOC_PATH| + "/settings.html"
|
||||
wait-for: "#settings"
|
||||
assert-css: (".setting-line", {"position": "relative"})
|
||||
assert-css: (".setting-radio", {"cursor": "pointer"})
|
||||
|
||||
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
|
||||
compare-elements-position: (".sub form", "#settings", ("x"))
|
||||
@ -322,4 +322,4 @@ reload:
|
||||
set-window-size: (300, 1000)
|
||||
click: "#settings-menu"
|
||||
wait-for: "#settings"
|
||||
assert-css: (".setting-line", {"position": "relative"})
|
||||
assert-css: (".setting-radio", {"cursor": "pointer"})
|
||||
|
@ -1,18 +0,0 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
struct Struct;
|
||||
trait Trait {}
|
||||
impl Trait for Struct {}
|
||||
impl Trait for u32 {}
|
||||
|
||||
fn foo() -> impl Trait { Struct }
|
||||
//~^ ERROR E0746
|
||||
|
||||
fn bar() -> impl Trait { //~ ERROR E0746
|
||||
if true {
|
||||
return 0;
|
||||
}
|
||||
42
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct Struct;
|
||||
trait Trait {}
|
||||
impl Trait for Struct {}
|
||||
|
@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn foo() -> dyn Trait { Struct }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn foo() -> impl Trait { Struct }
|
||||
| ~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/E0746.rs:11:13
|
||||
@ -16,11 +19,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bar() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bar() -> impl Trait {
|
||||
| ~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bar() -> Box<dyn Trait> {
|
||||
LL | if true {
|
||||
LL ~ return Box::new(0);
|
||||
LL | }
|
||||
LL ~ Box::new(42)
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn bax() -> dyn Trait { //~ ERROR E0746
|
||||
if true {
|
||||
Struct
|
||||
} else {
|
||||
42 //~ ERROR `if` and `else` have incompatible types
|
||||
42
|
||||
}
|
||||
}
|
||||
fn bam() -> Box<dyn Trait> {
|
||||
|
@ -46,11 +46,10 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bap() -> Trait { Struct }
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn bap() -> impl Trait { Struct }
|
||||
| ~~~~~~~~~~
|
||||
LL | fn bap() -> Box<Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
|
||||
@ -58,11 +57,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn ban() -> dyn Trait { Struct }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn ban() -> impl Trait { Struct }
|
||||
| ~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13
|
||||
@ -70,14 +72,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bak() -> dyn Trait { unimplemented!() }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bak() -> impl Trait { unimplemented!() }
|
||||
| ~~~~~~~~~~
|
||||
help: use a boxed trait object if all return paths implement trait `Trait`
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn bak() -> Box<dyn Trait> { unimplemented!() }
|
||||
| ++++ +
|
||||
LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) }
|
||||
| ++++ + +++++++++ +
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
|
||||
@ -85,34 +87,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bal() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl Trait` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bal() -> Box<dyn Trait> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn bal() -> impl Trait {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | return Box::new(Struct);
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
LL ~ fn bal() -> Box<dyn Trait> {
|
||||
LL | if true {
|
||||
LL ~ return Box::new(Struct);
|
||||
LL | }
|
||||
LL ~ Box::new(42)
|
||||
|
|
||||
LL | Box::new(42)
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9
|
||||
|
|
||||
LL | / if true {
|
||||
LL | | Struct
|
||||
| | ------ expected because of this
|
||||
LL | | } else {
|
||||
LL | | 42
|
||||
| | ^^ expected `Struct`, found integer
|
||||
LL | | }
|
||||
| |_____- `if` and `else` have incompatible types
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:13
|
||||
@ -120,22 +106,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bax() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl Trait` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bax() -> Box<dyn Trait> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn bax() -> impl Trait {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | Box::new(Struct)
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
LL ~ fn bax() -> Box<dyn Trait> {
|
||||
LL | if true {
|
||||
LL ~ Box::new(Struct)
|
||||
LL | } else {
|
||||
LL ~ Box::new(42)
|
||||
|
|
||||
LL | Box::new(42)
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16
|
||||
@ -279,11 +261,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bat() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bat() -> impl Trait {
|
||||
| ~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bat() -> Box<dyn Trait> {
|
||||
LL | if true {
|
||||
LL ~ return Box::new(0);
|
||||
LL | }
|
||||
LL ~ Box::new(42)
|
||||
|
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13
|
||||
@ -291,13 +280,20 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bay() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bay() -> impl Trait {
|
||||
| ~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bay() -> Box<dyn Trait> {
|
||||
LL | if true {
|
||||
LL ~ Box::new(0)
|
||||
LL | } else {
|
||||
LL ~ Box::new(42)
|
||||
|
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308, E0746.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -77,7 +77,7 @@ fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed
|
||||
fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
|
||||
match 13 {
|
||||
0 => 0i32,
|
||||
1 => 1u32, //~ ERROR `match` arms have incompatible types
|
||||
1 => 1u32,
|
||||
_ => 2u32,
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@ fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed
|
||||
if false {
|
||||
0i32
|
||||
} else {
|
||||
1u32 //~ ERROR `if` and `else` have incompatible types
|
||||
1u32
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,39 +171,20 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn hat() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn hat() -> Box<dyn std::fmt::Display> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn hat() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | return Box::new(0i32);
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
LL ~ fn hat() -> Box<dyn std::fmt::Display> {
|
||||
LL | match 13 {
|
||||
LL | 0 => {
|
||||
LL ~ return Box::new(0i32);
|
||||
LL | }
|
||||
LL | _ => {
|
||||
LL ~ Box::new(1u32)
|
||||
|
|
||||
LL | Box::new(1u32)
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
|
||||
|
|
||||
LL | / match 13 {
|
||||
LL | | 0 => 0i32,
|
||||
| | ---- this is found to be of type `i32`
|
||||
LL | | 1 => 1u32,
|
||||
| | ^^^^ expected `i32`, found `u32`
|
||||
LL | | _ => 2u32,
|
||||
LL | | }
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
|
|
||||
LL | 1 => 1i32,
|
||||
| ~~~
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
|
||||
@ -211,43 +192,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn pug() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn pug() -> Box<dyn std::fmt::Display> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn pug() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | 0 => Box::new(0i32),
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
LL ~ fn pug() -> Box<dyn std::fmt::Display> {
|
||||
LL | match 13 {
|
||||
LL ~ 0 => Box::new(0i32),
|
||||
LL ~ 1 => Box::new(1u32),
|
||||
LL ~ _ => Box::new(2u32),
|
||||
|
|
||||
LL | 1 => Box::new(1u32),
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
|
|
||||
LL | _ => Box::new(2u32),
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
|
||||
|
|
||||
LL | / if false {
|
||||
LL | | 0i32
|
||||
| | ---- expected because of this
|
||||
LL | | } else {
|
||||
LL | | 1u32
|
||||
| | ^^^^ expected `i32`, found `u32`
|
||||
LL | | }
|
||||
| |_____- `if` and `else` have incompatible types
|
||||
|
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
|
|
||||
LL | 1i32
|
||||
| ~~~
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
|
||||
@ -255,24 +211,20 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn man() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn man() -> Box<dyn std::fmt::Display> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn man() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | Box::new(0i32)
|
||||
| +++++++++ +
|
||||
help: ... and box this value
|
||||
LL ~ fn man() -> Box<dyn std::fmt::Display> {
|
||||
LL | if false {
|
||||
LL ~ Box::new(0i32)
|
||||
LL | } else {
|
||||
LL ~ Box::new(1u32)
|
||||
|
|
||||
LL | Box::new(1u32)
|
||||
| +++++++++ +
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0746.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
@ -4,14 +4,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | dyn AbstractRenderer
|
||||
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | impl AbstractRenderer
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
help: use a boxed trait object if all return paths implement trait `AbstractRenderer`
|
||||
LL ~ Box<dyn AbstractRenderer>
|
||||
LL |
|
||||
LL | {
|
||||
LL | match 0 {
|
||||
LL ~ _ => Box::new(unimplemented!())
|
||||
|
|
||||
LL | Box<dyn AbstractRenderer>
|
||||
| ++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
16
tests/ui/self/arbitrary-self-from-method-substs.rs
Normal file
16
tests/ui/self/arbitrary-self-from-method-substs.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
struct Foo(u32);
|
||||
impl Foo {
|
||||
fn get<R: Deref<Target=Self>>(self: R) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut foo = Foo(1);
|
||||
foo.get::<&Foo>();
|
||||
//~^ ERROR mismatched types
|
||||
}
|
9
tests/ui/self/arbitrary-self-from-method-substs.stderr
Normal file
9
tests/ui/self/arbitrary-self-from-method-substs.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/arbitrary-self-from-method-substs.rs:14:5
|
||||
|
|
||||
LL | foo.get::<&Foo>();
|
||||
| ^^^ expected `&Foo`, found `Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,15 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Tait<'a> = impl Sized + 'a;
|
||||
|
||||
fn foo<'a, 'b>() {
|
||||
if false {
|
||||
if { return } {
|
||||
let y: Tait<'b> = 1i32;
|
||||
//~^ ERROR concrete type differs from previous defining opaque type use
|
||||
}
|
||||
}
|
||||
let x: Tait<'a> = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error: concrete type differs from previous defining opaque type use
|
||||
--> $DIR/different_defining_uses_never_type-2.rs:8:31
|
||||
|
|
||||
LL | let y: Tait<'b> = 1i32;
|
||||
| ^^^^ expected `()`, got `i32`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different_defining_uses_never_type-2.rs:12:23
|
||||
|
|
||||
LL | let x: Tait<'a> = ();
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,15 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Tait<T> = impl Sized;
|
||||
|
||||
fn foo<T, U>() {
|
||||
if false {
|
||||
if { return } {
|
||||
let y: Tait<U> = 1i32;
|
||||
//~^ ERROR concrete type differs from previous defining opaque type use
|
||||
}
|
||||
}
|
||||
let x: Tait<T> = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error: concrete type differs from previous defining opaque type use
|
||||
--> $DIR/different_defining_uses_never_type-3.rs:8:30
|
||||
|
|
||||
LL | let y: Tait<U> = 1i32;
|
||||
| ^^^^ expected `()`, got `i32`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different_defining_uses_never_type-3.rs:12:22
|
||||
|
|
||||
LL | let x: Tait<T> = ();
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -8,6 +8,7 @@ type X<A, B> = impl Into<&'static A>;
|
||||
|
||||
fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
|
||||
//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
|
||||
//~| ERROR concrete type differs from previous defining opaque type use
|
||||
(a, a)
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,15 @@ help: consider introducing a `where` clause, but there might be an alternative b
|
||||
LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
|
||||
| ++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
error: concrete type differs from previous defining opaque type use
|
||||
--> $DIR/multiple-def-uses-in-one-fn.rs:9:45
|
||||
|
|
||||
LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected `&B`, got `&A`
|
||||
| this expression supplies two conflicting concrete types for the same opaque type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -8,7 +8,6 @@ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a {
|
||||
move || println!("{a}")
|
||||
} else {
|
||||
Box::new(move || println!("{}", b))
|
||||
//~^ ERROR `if` and `else` have incompatible types
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,42 +1,21 @@
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/box-instead-of-dyn-fn.rs:10:9
|
||||
|
|
||||
LL | / if a % 2 == 0 {
|
||||
LL | | move || println!("{a}")
|
||||
| | -----------------------
|
||||
| | |
|
||||
| | the expected closure
|
||||
| | expected because of this
|
||||
LL | | } else {
|
||||
LL | | Box::new(move || println!("{}", b))
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found `Box<[closure@box-instead-of-dyn-fn.rs:10:18]>`
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____- `if` and `else` have incompatible types
|
||||
|
|
||||
= note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:16]`
|
||||
found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:25]>`
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/box-instead-of-dyn-fn.rs:5:56
|
||||
|
|
||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a {
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||
= note: if all the returned values were of the same type you could use `impl Fn() + 'a` as the return type
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
= note: you can create a new `enum` with a variant for each returned type
|
||||
help: return a boxed trait object instead
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
|
||||
| ++++ +
|
||||
help: ... and box this value
|
||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
|
||||
LL |
|
||||
LL | if a % 2 == 0 {
|
||||
LL ~ Box::new(move || println!("{a}"))
|
||||
|
|
||||
LL | Box::new(move || println!("{a}"))
|
||||
| +++++++++ +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
Some errors have detailed explanations: E0308, E0746.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0746`.
|
||||
|
@ -4,11 +4,10 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 10:70]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a`
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
|
||||
| ++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
|
||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||
help: use `impl Foo<'a>` as the return type, as all return paths are of type `Box<_>`, which implements `Foo<'a>`
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> {
|
||||
| ~~~~~~~~~~~~
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> {
|
||||
| ++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user