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:
bors 2023-05-23 12:47:51 +00:00
commit b08148f6a7
46 changed files with 614 additions and 566 deletions

View File

@ -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);
}

View File

@ -478,6 +478,7 @@ pub enum StashKey {
MaybeFruTypo,
CallAssocMethod,
TraitMissingMethod,
OpaqueHiddenTypeMismatch,
}
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {

View File

@ -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();
}
}
}

View File

@ -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.

View File

@ -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
);
}
}
}
}

View File

@ -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,
);
}
}
}

View File

@ -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);

View File

@ -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(),
});
}
}
}
}

View File

@ -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,

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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>,

View File

@ -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);

View 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
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View 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
}
}

View 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
}
}

View File

@ -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() {
}

View 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
}
}

View 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
}
}

View File

@ -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

View File

@ -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"})

View File

@ -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() {}

View File

@ -1,5 +1,5 @@
// run-rustfix
#![allow(dead_code)]
struct Struct;
trait Trait {}
impl Trait for Struct {}

View File

@ -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

View File

@ -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> {

View File

@ -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`.

View File

@ -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
}
}

View File

@ -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`.

View File

@ -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

View 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
}

View 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`.

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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)
}

View File

@ -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`.

View File

@ -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
}
}

View File

@ -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`.

View File

@ -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

View File

@ -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