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
46 changed files with 614 additions and 566 deletions
|
@ -152,8 +152,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
||||||
prev.report_mismatch(
|
prev.report_mismatch(
|
||||||
&OpaqueHiddenType { ty, span: concrete_type.span },
|
&OpaqueHiddenType { ty, span: concrete_type.span },
|
||||||
|
opaque_type_key.def_id,
|
||||||
infcx.tcx,
|
infcx.tcx,
|
||||||
)
|
)
|
||||||
|
.emit()
|
||||||
});
|
});
|
||||||
prev.ty = infcx.tcx.ty_error(guar);
|
prev.ty = infcx.tcx.ty_error(guar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,6 +478,7 @@ pub enum StashKey {
|
||||||
MaybeFruTypo,
|
MaybeFruTypo,
|
||||||
CallAssocMethod,
|
CallAssocMethod,
|
||||||
TraitMissingMethod,
|
TraitMissingMethod,
|
||||||
|
OpaqueHiddenTypeMismatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
|
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");
|
debug!(?concrete_type, "found constraint");
|
||||||
if let Some(prev) = &mut self.found {
|
if let Some(prev) = &mut self.found {
|
||||||
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
|
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);
|
prev.ty = self.tcx.ty_error(guar);
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// Only check against typeck if we didn't already error
|
||||||
if !hidden.ty.references_error() {
|
if !hidden.ty.references_error() {
|
||||||
for concrete_type in locator.typeck_types {
|
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()
|
&& !(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
|
if concrete_type.ty != self.found.ty
|
||||||
&& !(concrete_type, self.found).references_error()
|
&& !(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);
|
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.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
fcx.check_return_expr(&body.value, false);
|
fcx.check_return_expr(&body.value, false);
|
||||||
}
|
|
||||||
|
|
||||||
// We insert the deferred_generator_interiors entry after visiting the body.
|
// We insert the deferred_generator_interiors entry after visiting the body.
|
||||||
// This ensures that all nested generators appear before the entry of this generator.
|
// 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
|
self_ty, method_self_ty, self.span, pick
|
||||||
);
|
);
|
||||||
let cause = self.cause(
|
let cause = self.cause(
|
||||||
self.span,
|
self.self_expr.span,
|
||||||
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
|
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
|
||||||
assoc_item: pick.item,
|
assoc_item: pick.item,
|
||||||
param_env: self.param_env,
|
param_env: self.param_env,
|
||||||
|
@ -482,7 +482,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||||
Ok(InferOk { obligations, value: () }) => {
|
Ok(InferOk { obligations, value: () }) => {
|
||||||
self.register_predicates(obligations);
|
self.register_predicates(obligations);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
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!(
|
span_bug!(
|
||||||
self.span,
|
self.span,
|
||||||
"{} was a subtype of {} but now is not?",
|
"{} was a subtype of {} but now is not?",
|
||||||
|
@ -492,6 +500,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: this returns the *unnormalized* predicates and method sig. Because of
|
// NOTE: this returns the *unnormalized* predicates and method sig. Because of
|
||||||
// inference guessing, the predicates and method signature can't be normalized
|
// inference guessing, the predicates and method signature can't be normalized
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use crate::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use hir::def_id::LocalDefId;
|
use hir::def_id::LocalDefId;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::{ErrorGuaranteed, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
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 =
|
wbcx.typeck_results.treat_byte_string_as_slice =
|
||||||
mem::take(&mut self.typeck_results.borrow_mut().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);
|
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
|
||||||
|
|
||||||
self.tcx.arena.alloc(wbcx.typeck_results)
|
self.tcx.arena.alloc(wbcx.typeck_results)
|
||||||
|
@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
) -> WritebackCx<'cx, 'tcx> {
|
) -> WritebackCx<'cx, 'tcx> {
|
||||||
let owner = body.id().hir_id.owner;
|
let owner = body.id().hir_id.owner;
|
||||||
|
|
||||||
WritebackCx {
|
let mut wbcx = WritebackCx {
|
||||||
fcx,
|
fcx,
|
||||||
typeck_results: ty::TypeckResults::new(owner),
|
typeck_results: ty::TypeckResults::new(owner),
|
||||||
body,
|
body,
|
||||||
rustc_dump_user_substs,
|
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> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
|
let hidden_type =
|
||||||
|
self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
|
||||||
opaque_type_key,
|
opaque_type_key,
|
||||||
self.fcx.infcx.tcx,
|
self.tcx(),
|
||||||
true,
|
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());
|
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
|
||||||
let num = CrateNum::new(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()) {
|
if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
|
||||||
|
// 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();
|
let crate_name0 = root.name();
|
||||||
if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) {
|
|
||||||
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
|
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
|
||||||
} else {
|
} else {
|
||||||
Err(CrateError::SymbolConflictsCurrent(crate_name0))
|
Err(CrateError::NotFound(root.name()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.metas.push(None);
|
self.metas.push(None);
|
||||||
|
|
|
@ -961,6 +961,7 @@ pub(crate) enum CrateError {
|
||||||
DlSym(String),
|
DlSym(String),
|
||||||
LocatorCombined(Box<CombinedLocatorError>),
|
LocatorCombined(Box<CombinedLocatorError>),
|
||||||
NonDylibPlugin(Symbol),
|
NonDylibPlugin(Symbol),
|
||||||
|
NotFound(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MetadataError<'a> {
|
enum MetadataError<'a> {
|
||||||
|
@ -1131,6 +1132,18 @@ impl CrateError {
|
||||||
CrateError::NonDylibPlugin(crate_name) => {
|
CrateError::NonDylibPlugin(crate_name) => {
|
||||||
sess.emit_err(errors::NoDylibPlugin { span, 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::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::steal::Steal;
|
use rustc_data_structures::steal::Steal;
|
||||||
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
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 as hir;
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||||
|
@ -1439,14 +1439,26 @@ pub struct OpaqueHiddenType<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> 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.
|
// Found different concrete types for the opaque type.
|
||||||
let sub_diag = if self.span == other.span {
|
let sub_diag = if self.span == other.span {
|
||||||
TypeMismatchReason::ConflictType { span: self.span }
|
TypeMismatchReason::ConflictType { span: self.span }
|
||||||
} else {
|
} else {
|
||||||
TypeMismatchReason::PreviousUse { span: self.span }
|
TypeMismatchReason::PreviousUse { span: self.span }
|
||||||
};
|
};
|
||||||
tcx.sess.emit_err(OpaqueHiddenTypeMismatch {
|
tcx.sess.create_err(OpaqueHiddenTypeMismatch {
|
||||||
self_ty: self.ty,
|
self_ty: self.ty,
|
||||||
other_ty: other.ty,
|
other_ty: other.ty,
|
||||||
other_span: other.span,
|
other_span: other.span,
|
||||||
|
|
|
@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// this field will be set to `Some(ErrorGuaranteed)`.
|
/// this field will be set to `Some(ErrorGuaranteed)`.
|
||||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||||
|
|
||||||
/// All the opaque types that have hidden types set
|
/// All the opaque types that have hidden types set by this function.
|
||||||
/// by this function. We also store the
|
/// We also store the type here, so that the compiler can use it as a hint
|
||||||
/// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
|
/// for figuring out hidden types, even if they are only set in dead code
|
||||||
/// even if they are only set in dead code (which doesn't show up in MIR).
|
/// (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>>,
|
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||||
|
|
||||||
/// Tracks the minimum captures required for a closure;
|
/// Tracks the minimum captures required for a closure;
|
||||||
|
|
|
@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
|
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
|
||||||
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
use rustc_middle::ty::{self, Ty, UpvarSubsts};
|
use rustc_middle::ty::{self, Ty, UpvarSubsts};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
let (op,ty) = (Operand::Move(discr), discr_ty);
|
let (op,ty) = (Operand::Move(discr), discr_ty);
|
||||||
|
|
||||||
if let Abi::Scalar(scalar) = layout.unwrap().abi{
|
if let Abi::Scalar(scalar) = layout.unwrap().abi
|
||||||
if let Primitive::Int(_, signed) = scalar.primitive() {
|
&& !scalar.is_always_valid(&this.tcx)
|
||||||
let range = scalar.valid_range(&this.tcx);
|
&& let Primitive::Int(int_width, _signed) = scalar.primitive()
|
||||||
// FIXME: Handle wraparound cases too.
|
{
|
||||||
if range.end >= range.start {
|
let unsigned_ty = int_width.to_ty(this.tcx, false);
|
||||||
let mut assumer = |range: u128, bin_op: BinOp| {
|
let unsigned_place = this.temp(unsigned_ty, expr_span);
|
||||||
// We will be overwriting this val if our scalar is signed value
|
this.cfg.push_assign(
|
||||||
// because sign extension on unsigned types might cause unintended things
|
block,
|
||||||
let mut range_val =
|
source_info,
|
||||||
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
|
unsigned_place,
|
||||||
|
Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
|
||||||
|
|
||||||
let bool_ty = this.tcx.types.bool;
|
let bool_ty = this.tcx.types.bool;
|
||||||
if signed {
|
let range = scalar.valid_range(&this.tcx);
|
||||||
let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
|
let merge_op =
|
||||||
let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
|
if range.start <= range.end {
|
||||||
let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
|
BinOp::BitAnd
|
||||||
range_val = ConstantKind::from_bits(
|
} else {
|
||||||
this.tcx,
|
BinOp::BitOr
|
||||||
truncated_val,
|
};
|
||||||
ty::ParamEnv::empty().and(discr_ty),
|
|
||||||
);
|
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 lit_op = this.literal_operand(expr.span, range_val);
|
||||||
let is_bin_op = this.temp(bool_ty, expr_span);
|
let is_bin_op = this.temp(bool_ty, expr_span);
|
||||||
this.cfg.push_assign(
|
this.cfg.push_assign(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
is_bin_op,
|
is_bin_op,
|
||||||
Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
|
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(
|
this.cfg.push(
|
||||||
block,
|
block,
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
|
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
|
||||||
Operand::Copy(is_bin_op),
|
Operand::Move(assert_place),
|
||||||
))),
|
))),
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
};
|
|
||||||
assumer(range.end, BinOp::Ge);
|
|
||||||
assumer(range.start, BinOp::Le);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(op,ty)
|
(op,ty)
|
||||||
|
|
|
@ -885,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
|
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ use rustc_middle::hir::map;
|
||||||
use rustc_middle::ty::error::TypeError::{self, Sorts};
|
use rustc_middle::ty::error::TypeError::{self, Sorts};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
|
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
|
||||||
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
|
GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable,
|
||||||
IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
|
ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||||
TypeSuperFoldable, TypeVisitableExt, TypeckResults,
|
TypeVisitableExt, TypeckResults,
|
||||||
};
|
};
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
|
@ -261,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
fn suggest_impl_trait(
|
fn suggest_impl_trait(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
span: Span,
|
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
@ -1792,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
fn suggest_impl_trait(
|
fn suggest_impl_trait(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
span: Span,
|
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match obligation.cause.code().peel_derives() {
|
let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
|
||||||
// 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 {
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let body = hir.body(*body_id);
|
let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
|
||||||
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 {
|
|
||||||
return false;
|
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.code(error_code!(E0746));
|
||||||
err.set_primary_message("return type cannot have an unboxed trait object");
|
err.set_primary_message("return type cannot have an unboxed trait object");
|
||||||
err.children.clear();
|
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 span = obligation.cause.span;
|
||||||
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
|
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
if only_never_return {
|
&& snip.starts_with("dyn ")
|
||||||
// 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`.
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
ret_ty.span,
|
span.with_hi(span.lo() + BytePos(4)),
|
||||||
format!(
|
"return an `impl Trait` instead of a `dyn Trait`, \
|
||||||
"use `impl {1}` as the return type, as all return paths are of type `{}`, \
|
if all returned values are the same type",
|
||||||
which implements `{1}`",
|
"impl ",
|
||||||
last_ty, trait_obj,
|
|
||||||
),
|
|
||||||
format!("impl {}", trait_obj),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
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,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
for (span, needs_box) in spans_and_needs_box {
|
}
|
||||||
if needs_box {
|
|
||||||
err.multipart_suggestion(
|
let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
|
||||||
"... and box this value",
|
|
||||||
|
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![
|
vec![
|
||||||
(span.shrink_to_lo(), "Box::new(".to_string()),
|
(span.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
(span.shrink_to_hi(), ")".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,
|
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");
|
|
||||||
}
|
|
||||||
true
|
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`
|
/// Collect the spans that we see the generic param `param_did`
|
||||||
struct ReplaceImplTraitVisitor<'a> {
|
struct ReplaceImplTraitVisitor<'a> {
|
||||||
ty_spans: &'a mut Vec<Span>,
|
ty_spans: &'a mut Vec<Span>,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
.setting-line {
|
.setting-line {
|
||||||
margin: 1.2em 0.6em;
|
margin: 1.2em 0.6em;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-radio input, .setting-check input {
|
.setting-radio input, .setting-check input {
|
||||||
|
@ -15,11 +14,6 @@
|
||||||
.setting-radio input {
|
.setting-radio input {
|
||||||
border-radius: 50%;
|
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 {
|
.setting-radio span, .setting-check span {
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
|
@ -52,6 +46,9 @@
|
||||||
.setting-check input:checked {
|
.setting-check input:checked {
|
||||||
background-color: var(--settings-input-color);
|
background-color: var(--settings-input-color);
|
||||||
border-width: 1px;
|
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 {
|
.setting-radio input:focus, .setting-check input:focus {
|
||||||
box-shadow: 0 0 1px 1px var(--settings-input-color);
|
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::num::{NonZeroU32, NonZeroI64};
|
||||||
use core::ptr::NonNull;
|
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
|
// CHECK-lABEL: @non_zero_eq
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn non_zero_eq(l: Option<NonZeroU32>, r: Option<NonZeroU32>) -> bool {
|
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
|
// CHECK-NEXT: ret i1
|
||||||
l == r
|
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 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 _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 _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
|
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
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
|
_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
|
_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
|
_4 = _3 as u8 (IntToInt); // 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(_4, const 1_u8); // 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(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||||
assume(_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
|
_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
|
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
|
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 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 _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 _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
|
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
|
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
|
_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
|
_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
|
_4 = _3 as u8 (IntToInt); // 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(_4, const 1_u8); // 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(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
|
||||||
assume(_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
|
_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
|
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
|
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 _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 _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 _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 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
|
let _8: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
|
||||||
scope 1 {
|
scope 1 {
|
||||||
|
@ -31,10 +31,9 @@ fn droppy() -> () {
|
||||||
StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
|
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
|
_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
|
_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
|
_6 = _5 as u8 (IntToInt); // 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(_6, const 2_u8); // 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(move _7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
|
||||||
assume(_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
|
_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
|
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.foo.built.after.mir
|
||||||
// EMIT_MIR enum_cast.bar.built.after.mir
|
// EMIT_MIR enum_cast.bar.built.after.mir
|
||||||
// EMIT_MIR enum_cast.boo.built.after.mir
|
// EMIT_MIR enum_cast.boo.built.after.mir
|
||||||
|
// EMIT_MIR enum_cast.far.built.after.mir
|
||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
A
|
A
|
||||||
|
@ -15,6 +16,11 @@ enum Boo {
|
||||||
A, B
|
A, B
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(i16)]
|
||||||
|
enum Far {
|
||||||
|
A, B
|
||||||
|
}
|
||||||
|
|
||||||
fn foo(foo: Foo) -> usize {
|
fn foo(foo: Foo) -> usize {
|
||||||
foo as usize
|
foo as usize
|
||||||
}
|
}
|
||||||
|
@ -27,6 +33,10 @@ fn boo(boo: Boo) -> usize {
|
||||||
boo as usize
|
boo as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn far(far: Far) -> isize {
|
||||||
|
far as isize
|
||||||
|
}
|
||||||
|
|
||||||
// EMIT_MIR enum_cast.droppy.built.after.mir
|
// EMIT_MIR enum_cast.droppy.built.after.mir
|
||||||
enum Droppy {
|
enum Droppy {
|
||||||
A, B, C
|
A, B, C
|
||||||
|
@ -46,5 +56,37 @@ fn droppy() {
|
||||||
let z = Droppy::B;
|
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() {
|
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 \
|
--crate-type=rlib \
|
||||||
--edition=2018 \
|
--edition=2018 \
|
||||||
c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
|
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
|
$(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.
|
// Now we go to the settings page to check that the CSS is loaded as expected.
|
||||||
go-to: "file://" + |DOC_PATH| + "/settings.html"
|
go-to: "file://" + |DOC_PATH| + "/settings.html"
|
||||||
wait-for: "#settings"
|
wait-for: "#settings"
|
||||||
assert-css: (".setting-line", {"position": "relative"})
|
assert-css: (".setting-radio", {"cursor": "pointer"})
|
||||||
|
|
||||||
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
|
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
|
||||||
compare-elements-position: (".sub form", "#settings", ("x"))
|
compare-elements-position: (".sub form", "#settings", ("x"))
|
||||||
|
@ -322,4 +322,4 @@ reload:
|
||||||
set-window-size: (300, 1000)
|
set-window-size: (300, 1000)
|
||||||
click: "#settings-menu"
|
click: "#settings-menu"
|
||||||
wait-for: "#settings"
|
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)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
struct Struct;
|
struct Struct;
|
||||||
trait Trait {}
|
trait Trait {}
|
||||||
impl Trait for Struct {}
|
impl Trait for Struct {}
|
||||||
|
|
|
@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||||
LL | fn foo() -> dyn Trait { Struct }
|
LL | fn foo() -> dyn Trait { Struct }
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn foo() -> impl Trait { Struct }
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/E0746.rs:11:13
|
--> $DIR/E0746.rs:11:13
|
||||||
|
@ -16,11 +19,18 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||||
LL | fn bar() -> dyn Trait {
|
LL | fn bar() -> dyn Trait {
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn bar() -> impl Trait {
|
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
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn bax() -> dyn Trait { //~ ERROR E0746
|
||||||
if true {
|
if true {
|
||||||
Struct
|
Struct
|
||||||
} else {
|
} else {
|
||||||
42 //~ ERROR `if` and `else` have incompatible types
|
42
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn bam() -> Box<dyn Trait> {
|
fn bam() -> Box<dyn Trait> {
|
||||||
|
|
|
@ -46,11 +46,10 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||||
LL | fn bap() -> Trait { Struct }
|
LL | fn bap() -> Trait { Struct }
|
||||||
| ^^^^^ doesn't have a size known at compile-time
|
| ^^^^^ 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: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn bap() -> impl Trait { Struct }
|
LL | fn bap() -> Box<Trait> { Box::new(Struct) }
|
||||||
| ~~~~~~~~~~
|
| ++++ + +++++++++ +
|
||||||
|
|
||||||
error[E0746]: return type cannot have an unboxed trait object
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
|
--> $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 }
|
LL | fn ban() -> dyn Trait { Struct }
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn ban() -> impl Trait { Struct }
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13
|
--> $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!() }
|
LL | fn bak() -> dyn Trait { unimplemented!() }
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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!() }
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
|
--> $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 {
|
LL | fn bal() -> dyn Trait {
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn bal() -> Box<dyn Trait> {
|
LL | fn bal() -> impl Trait {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
|
|
|
|
||||||
LL | return Box::new(Struct);
|
LL ~ fn bal() -> Box<dyn Trait> {
|
||||||
| +++++++++ +
|
LL | if true {
|
||||||
help: ... and box this value
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:13
|
--> $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 {
|
LL | fn bax() -> dyn Trait {
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn bax() -> Box<dyn Trait> {
|
LL | fn bax() -> impl Trait {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
|
|
|
|
||||||
LL | Box::new(Struct)
|
LL ~ fn bax() -> Box<dyn Trait> {
|
||||||
| +++++++++ +
|
LL | if true {
|
||||||
help: ... and box this value
|
LL ~ Box::new(Struct)
|
||||||
|
LL | } else {
|
||||||
|
LL ~ Box::new(42)
|
||||||
|
|
|
|
||||||
LL | Box::new(42)
|
|
||||||
| +++++++++ +
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16
|
--> $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 {
|
LL | fn bat() -> dyn Trait {
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn bat() -> impl Trait {
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13
|
--> $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 {
|
LL | fn bay() -> dyn Trait {
|
||||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
|
|
||||||
|
|
|
|
||||||
LL | fn bay() -> impl Trait {
|
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.
|
Some errors have detailed explanations: E0277, E0308, E0746.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
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
|
fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
|
||||||
match 13 {
|
match 13 {
|
||||||
0 => 0i32,
|
0 => 0i32,
|
||||||
1 => 1u32, //~ ERROR `match` arms have incompatible types
|
1 => 1u32,
|
||||||
_ => 2u32,
|
_ => 2u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed
|
||||||
if false {
|
if false {
|
||||||
0i32
|
0i32
|
||||||
} else {
|
} 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 {
|
LL | fn hat() -> dyn std::fmt::Display {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn hat() -> Box<dyn std::fmt::Display> {
|
LL | fn hat() -> impl std::fmt::Display {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
|
|
|
|
||||||
LL | return Box::new(0i32);
|
LL ~ fn hat() -> Box<dyn std::fmt::Display> {
|
||||||
| +++++++++ +
|
LL | match 13 {
|
||||||
help: ... and box this value
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
|
--> $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 {
|
LL | fn pug() -> dyn std::fmt::Display {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn pug() -> Box<dyn std::fmt::Display> {
|
LL | fn pug() -> impl std::fmt::Display {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
|
|
|
|
||||||
LL | 0 => Box::new(0i32),
|
LL ~ fn pug() -> Box<dyn std::fmt::Display> {
|
||||||
| +++++++++ +
|
LL | match 13 {
|
||||||
help: ... and box this value
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
|
--> $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 {
|
LL | fn man() -> dyn std::fmt::Display {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn man() -> Box<dyn std::fmt::Display> {
|
LL | fn man() -> impl std::fmt::Display {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
|
|
|
|
||||||
LL | Box::new(0i32)
|
LL ~ fn man() -> Box<dyn std::fmt::Display> {
|
||||||
| +++++++++ +
|
LL | if false {
|
||||||
help: ... and box this value
|
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.
|
Some errors have detailed explanations: E0308, E0746.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
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
|
LL | dyn AbstractRenderer
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^^^^^^^^ 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
|
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
|
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>) {
|
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 the trait bound `&'static B: From<&A>` is not satisfied
|
||||||
|
//~| ERROR concrete type differs from previous defining opaque type use
|
||||||
(a, a)
|
(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> {
|
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`.
|
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}")
|
move || println!("{a}")
|
||||||
} else {
|
} else {
|
||||||
Box::new(move || println!("{}", b))
|
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
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
--> $DIR/box-instead-of-dyn-fn.rs:5:56
|
--> $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 {
|
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
|
| ^^^^^^^^^^^^^ 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>
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
|
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
|
||||||
| ++++ +
|
| ~~~~
|
||||||
help: ... and box this value
|
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 this error, try `rustc --explain E0746`.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
|
||||||
|
|
|
@ -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> {
|
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
|
||||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^ 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: box the return type, and wrap all of the returned values in `Box::new`
|
||||||
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`
|
|
||||||
|
|
|
|
||||||
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
|
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> {
|
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
|
||||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^ 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: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||||
help: use `impl Foo<'a>` as the return type, as all return paths are of type `Box<_>`, which implements `Foo<'a>`
|
|
||||||
|
|
|
|
||||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> {
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue