Auto merge of #120283 - fmease:rollup-rk0f6r5, r=fmease

Rollup of 9 pull requests

Successful merges:

 - #112806 (Small code improvements in `collect_intra_doc_links.rs`)
 - #119766 (Split tait and impl trait in assoc items logic)
 - #120139 (Do not normalize closure signature when building `FnOnce` shim)
 - #120160 (Manually implement derived `NonZero` traits.)
 - #120171 (Fix assume and assert in jump threading)
 - #120183 (Add `#[coverage(off)]` to closures introduced by `#[test]` and `#[bench]`)
 - #120195 (add several resolution test cases)
 - #120259 (Split Diagnostics for Uncommon Codepoints: Add List to Display Characters Involved)
 - #120261 (Provide structured suggestion to use trait objects in some cases of `if` arm type divergence)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-01-23 22:44:44 +00:00
commit 0b7730105f
87 changed files with 1606 additions and 226 deletions

View File

@ -6,6 +6,7 @@
#![doc(rust_logo)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]

View File

@ -9,6 +9,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Level};
use rustc_expand::base::*;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
use std::assert_matches::assert_matches;
use std::iter;
use thin_vec::{thin_vec, ThinVec};
@ -182,6 +183,16 @@ pub fn expand_test_or_bench(
// creates $name: $expr
let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr);
// Adds `#[coverage(off)]` to a closure, so it won't be instrumented in
// `-Cinstrument-coverage` builds.
// This requires `#[allow_internal_unstable(coverage_attribute)]` on the
// corresponding macro declaration in `core::macros`.
let coverage_off = |mut expr: P<ast::Expr>| {
assert_matches!(expr.kind, ast::ExprKind::Closure(_));
expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp));
expr
};
let test_fn = if is_bench {
// A simple ident for a lambda
let b = Ident::from_str_and_span("b", attr_sp);
@ -190,8 +201,9 @@ pub fn expand_test_or_bench(
sp,
cx.expr_path(test_path("StaticBenchFn")),
thin_vec![
// #[coverage(off)]
// |b| self::test::assert_test_result(
cx.lambda1(
coverage_off(cx.lambda1(
sp,
cx.expr_call(
sp,
@ -206,7 +218,7 @@ pub fn expand_test_or_bench(
],
),
b,
), // )
)), // )
],
)
} else {
@ -214,8 +226,9 @@ pub fn expand_test_or_bench(
sp,
cx.expr_path(test_path("StaticTestFn")),
thin_vec![
// #[coverage(off)]
// || {
cx.lambda0(
coverage_off(cx.lambda0(
sp,
// test::assert_test_result(
cx.expr_call(
@ -230,7 +243,7 @@ pub fn expand_test_or_bench(
), // )
],
), // }
), // )
)), // )
],
)
};

View File

@ -682,7 +682,6 @@ fn codegen_stmt<'tcx>(
args,
ty::ClosureKind::FnOnce,
)
.expect("failed to normalize and resolve closure during codegen")
.polymorphize(fx.tcx);
let func_ref = fx.get_function_ref(instance);
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);

View File

@ -435,7 +435,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args,
ty::ClosureKind::FnOnce,
)
.expect("failed to normalize and resolve closure during codegen")
.polymorphize(bx.cx().tcx());
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
}

View File

@ -117,8 +117,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
def_id,
args,
ty::ClosureKind::FnOnce,
)
.ok_or_else(|| err_inval!(TooGeneric))?;
);
let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
self.write_pointer(fn_ptr, dest)?;
}

View File

@ -110,6 +110,14 @@ impl IntoDiagnosticArg for char {
}
}
impl IntoDiagnosticArg for Vec<char> {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::StrListSepByAnd(
self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(),
)
}
}
impl IntoDiagnosticArg for Symbol {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_ident_string().into_diagnostic_arg()

View File

@ -530,9 +530,13 @@ pub(super) fn type_of_opaque(
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. },
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
..
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:

View File

@ -23,6 +23,60 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed>
res
}
/// Checks "defining uses" of opaque `impl Trait` in associated types.
/// These can only be defined by associated items of the same trait.
#[instrument(skip(tcx), level = "debug")]
pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> Ty<'_> {
let mut parent_def_id = def_id;
while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
// Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
parent_def_id = tcx.local_parent(parent_def_id);
}
let impl_def_id = tcx.local_parent(parent_def_id);
match tcx.def_kind(impl_def_id) {
DefKind::Impl { .. } => {}
other => bug!("invalid impl trait in assoc type parent: {other:?}"),
}
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id);
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => {
locator.check(assoc_id.expect_local(), ImplTraitSource::AssocTy)
}
// Associated types don't have bodies, so they can't constrain hidden types
ty::AssocKind::Type => {}
}
}
if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty)
&& !(concrete_type, hidden).references_error()
{
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
}
}
}
hidden.ty
} else {
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(parent_def_id.to_def_id()),
what: "impl",
});
Ty::new_error(tcx, reported)
}
}
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
/// laid for "higher-order pattern unification".
/// This ensures that inference is tractable.
@ -128,9 +182,15 @@ struct TaitConstraintLocator<'tcx> {
typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
}
#[derive(Debug)]
enum ImplTraitSource {
AssocTy,
TyAlias,
}
impl TaitConstraintLocator<'_> {
#[instrument(skip(self), level = "debug")]
fn check(&mut self, item_def_id: LocalDefId) {
fn check(&mut self, item_def_id: LocalDefId, source: ImplTraitSource) {
// Don't try to check items that cannot possibly constrain the type.
if !self.tcx.has_typeck_results(item_def_id) {
debug!("no constraint: no typeck results");
@ -182,7 +242,13 @@ impl TaitConstraintLocator<'_> {
continue;
}
constrained = true;
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
let opaque_types_defined_by = match source {
ImplTraitSource::AssocTy => {
self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id)
}
ImplTraitSource::TyAlias => self.tcx.opaque_types_defined_by(item_def_id),
};
if !opaque_types_defined_by.contains(&self.def_id) {
self.tcx.dcx().emit_err(TaitForwardCompat {
span: hidden_type.span,
item_span: self
@ -240,7 +306,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Closure(closure) = ex.kind {
self.check(closure.def_id);
self.check(closure.def_id, ImplTraitSource::TyAlias);
}
intravisit::walk_expr(self, ex);
}
@ -248,7 +314,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_item(self, it);
}
}
@ -256,13 +322,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.owner_id);
self.check(it.owner_id.def_id);
self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_trait_item(self, it);
}
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {

View File

@ -44,7 +44,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_no_capture_closure(err, expected, expr_ty)
|| self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
|| self.suggest_boxing_when_appropriate(
err,
expr.peel_blocks().span,
expr.hir_id,
expected,
expr_ty,
)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected)
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)

View File

@ -294,8 +294,9 @@ impl<T> Trait<T> for X {
);
}
}
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias))
if alias.def_id.is_local()
(_, ty::Alias(ty::Opaque, opaque_ty))
| (ty::Alias(ty::Opaque, opaque_ty), _) => {
if opaque_ty.def_id.is_local()
&& matches!(
tcx.def_kind(body_owner_def_id),
DefKind::Fn
@ -303,21 +304,74 @@ impl<T> Trait<T> for X {
| DefKind::Const
| DefKind::AssocFn
| DefKind::AssocConst
) =>
{
if tcx.is_type_alias_impl_trait(alias.def_id) {
if !tcx
)
&& tcx.is_type_alias_impl_trait(opaque_ty.def_id)
&& !tcx
.opaque_types_defined_by(body_owner_def_id.expect_local())
.contains(&alias.def_id.expect_local())
{
let sp = tcx
.def_ident_span(body_owner_def_id)
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
diag.span_note(
sp,
"\
this item must have the opaque type in its signature \
in order to be able to register hidden types",
.contains(&opaque_ty.def_id.expect_local())
{
let sp = tcx
.def_ident_span(body_owner_def_id)
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
diag.span_note(
sp,
"this item must have the opaque type in its signature in order to \
be able to register hidden types",
);
}
// If two if arms can be coerced to a trait object, provide a structured
// suggestion.
let ObligationCauseCode::IfExpression(cause) = cause.code() else {
return;
};
let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else {
return;
};
let Some(then) = blk.expr else {
return;
};
let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else {
return;
};
let Some(else_) = blk.expr else {
return;
};
let expected = match values.found.kind() {
ty::Alias(..) => values.expected,
_ => values.found,
};
let preds = tcx.explicit_item_bounds(opaque_ty.def_id);
for (pred, _span) in preds.skip_binder() {
let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
else {
continue;
};
if trait_predicate.polarity != ty::ImplPolarity::Positive {
continue;
}
let def_id = trait_predicate.def_id();
let mut impl_def_ids = vec![];
tcx.for_each_relevant_impl(def_id, expected, |did| {
impl_def_ids.push(did)
});
if let [_] = &impl_def_ids[..] {
let trait_name = tcx.item_name(def_id);
diag.multipart_suggestion(
format!(
"`{expected}` implements `{trait_name}` so you can box \
both arms and coerce to the trait object \
`Box<dyn {trait_name}>`",
),
vec![
(then.span.shrink_to_lo(), "Box::new(".to_string()),
(
then.span.shrink_to_hi(),
format!(") as Box<dyn {}>", tcx.def_path_str(def_id)),
),
(else_.span.shrink_to_lo(), "Box::new(".to_string()),
(else_.span.shrink_to_hi(), ")".to_string()),
],
MachineApplicable,
);
}
}
@ -330,6 +384,38 @@ impl<T> Trait<T> for X {
);
}
}
(ty::Adt(_, _), ty::Adt(def, args))
if let ObligationCauseCode::IfExpression(cause) = cause.code()
&& let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id)
&& let Some(then) = blk.expr
&& def.is_box()
&& let boxed_ty = args.type_at(0)
&& let ty::Dynamic(t, _, _) = boxed_ty.kind()
&& let Some(def_id) = t.principal_def_id()
&& let mut impl_def_ids = vec![]
&& let _ =
tcx.for_each_relevant_impl(def_id, values.expected, |did| {
impl_def_ids.push(did)
})
&& let [_] = &impl_def_ids[..] =>
{
// We have divergent if/else arms where the expected value is a type that
// implements the trait of the found boxed trait object.
diag.multipart_suggestion(
format!(
"`{}` implements `{}` so you can box it to coerce to the trait \
object `{}`",
values.expected,
tcx.item_name(def_id),
values.found,
),
vec![
(then.span.shrink_to_lo(), "Box::new(".to_string()),
(then.span.shrink_to_hi(), ")".to_string()),
],
MachineApplicable,
);
}
_ => {}
}
debug!(

View File

@ -240,7 +240,10 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of
lint_identifier_non_ascii_char = identifier contains non-ASCII characters
lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
[one] an uncommon Unicode codepoint
*[other] uncommon Unicode codepoints
}: {$codepoints}
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level

View File

@ -1107,7 +1107,10 @@ pub struct IdentifierNonAsciiChar;
#[derive(LintDiagnostic)]
#[diag(lint_identifier_uncommon_codepoints)]
pub struct IdentifierUncommonCodepoints;
pub struct IdentifierUncommonCodepoints {
pub codepoints: Vec<char>,
pub codepoints_len: usize,
}
#[derive(LintDiagnostic)]
#[diag(lint_confusable_identifier_pair)]

View File

@ -190,7 +190,17 @@ impl EarlyLintPass for NonAsciiIdents {
if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{
cx.emit_span_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints);
let codepoints: Vec<_> = symbol_str
.chars()
.filter(|c| !GeneralSecurityProfile::identifier_allowed(*c))
.collect();
let codepoints_len = codepoints.len();
cx.emit_span_lint(
UNCOMMON_CODEPOINTS,
sp,
IdentifierUncommonCodepoints { codepoints, codepoints_len },
);
}
}

View File

@ -343,6 +343,15 @@ rustc_queries! {
}
}
query impl_trait_in_assoc_types_defined_by(
key: LocalDefId
) -> &'tcx ty::List<LocalDefId> {
desc {
|tcx| "computing the opaque types defined by `{}`",
tcx.def_path_str(key.to_def_id())
}
}
/// Returns the list of bounds that can be used for
/// `SelectionCandidate::ProjectionCandidate(_)` and
/// `ProjectionTyCandidate::TraitDef`.

View File

@ -530,12 +530,12 @@ impl<'tcx> Instance<'tcx> {
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
requested_kind: ty::ClosureKind,
) -> Option<Instance<'tcx>> {
) -> Instance<'tcx> {
let actual_kind = args.as_closure().kind();
match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, args),
_ => Some(Instance::new(def_id, args)),
_ => Instance::new(def_id, args),
}
}
@ -550,7 +550,7 @@ impl<'tcx> Instance<'tcx> {
tcx: TyCtxt<'tcx>,
closure_did: DefId,
args: ty::GenericArgsRef<'tcx>,
) -> Option<Instance<'tcx>> {
) -> Instance<'tcx> {
let fn_once = tcx.require_lang_item(LangItem::FnOnce, None);
let call_once = tcx
.associated_items(fn_once)
@ -564,14 +564,12 @@ impl<'tcx> Instance<'tcx> {
let self_ty = Ty::new_closure(tcx, closure_did, args);
let sig = args.as_closure().sig();
let sig =
tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?;
assert_eq!(sig.inputs().len(), 1);
let args = tcx.mk_args_trait(self_ty, [sig.inputs()[0].into()]);
let tupled_inputs_ty = args.as_closure().sig().map_bound(|sig| sig.inputs()[0]);
let tupled_inputs_ty = tcx.instantiate_bound_regions_with_erased(tupled_inputs_ty);
let args = tcx.mk_args_trait(self_ty, [tupled_inputs_ty.into()]);
debug!(?self_ty, ?sig);
Some(Instance { def, args })
debug!(?self_ty, args=?tupled_inputs_ty.tuple_fields());
Instance { def, args }
}
pub fn try_resolve_item_for_coroutine(

View File

@ -20,6 +20,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
@call(mir_storage_dead, args) => {
Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
},
@call(mir_assume, args) => {
let op = self.parse_operand(args[0])?;
Ok(StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(op))))
},
@call(mir_deinit, args) => {
Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
},

View File

@ -566,11 +566,6 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
cost: &CostChecker<'_, 'tcx>,
depth: usize,
) {
let register_opportunity = |c: Condition| {
debug!(?bb, ?c.target, "register");
self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target })
};
let term = self.body.basic_blocks[bb].terminator();
let place_to_flood = match term.kind {
// We come from a target, so those are not possible.
@ -592,16 +587,8 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
// Flood the overwritten place, and progress through.
TerminatorKind::Drop { place: destination, .. }
| TerminatorKind::Call { destination, .. } => Some(destination),
// Treat as an `assume(cond == expected)`.
TerminatorKind::Assert { ref cond, expected, .. } => {
if let Some(place) = cond.place()
&& let Some(conditions) = state.try_get(place.as_ref(), self.map)
{
let expected = if expected { ScalarInt::TRUE } else { ScalarInt::FALSE };
conditions.iter_matches(expected).for_each(register_opportunity);
}
None
}
// Ignore, as this can be a no-op at codegen time.
TerminatorKind::Assert { .. } => None,
};
// We can recurse through this terminator.

View File

@ -783,8 +783,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
def_id,
args,
ty::ClosureKind::FnOnce,
)
.expect("failed to normalize and resolve closure during codegen");
);
if should_codegen_locally(self.tcx, &instance) {
self.output.push(create_fn_mono_item(self.tcx, instance, span));
}

View File

@ -464,7 +464,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
let def_id = def.0.internal(&mut *tables, tcx);
let args_ref = args.internal(&mut *tables, tcx);
let closure_kind = kind.internal(&mut *tables, tcx);
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
Some(
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind)
.stable(&mut *tables),
)
}
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {

View File

@ -1028,6 +1028,7 @@ symbols! {
minnumf32,
minnumf64,
mips_target_feature,
mir_assume,
mir_basic_block,
mir_call,
mir_cast_transmute,

View File

@ -265,7 +265,12 @@ fn resolve_associated_item<'tcx>(
match *rcvr_args.type_at(0).kind() {
ty::Closure(closure_def_id, args) => {
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Instance::resolve_closure(tcx, closure_def_id, args, trait_closure_kind)
Some(Instance::resolve_closure(
tcx,
closure_def_id,
args,
trait_closure_kind,
))
}
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),

View File

@ -118,6 +118,69 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
}
TaitInBodyFinder { collector: self }.visit_expr(body);
}
fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) {
if !self.seen.insert(alias_ty.def_id.expect_local()) {
return;
}
// TAITs outside their defining scopes are ignored.
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
trace!(?origin);
match origin {
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
if !in_assoc_ty {
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
return;
}
}
}
}
self.opaques.push(alias_ty.def_id.expect_local());
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
// Only check that the parent generics of the TAIT/RPIT are unique.
// the args owned by the opaque are going to always be duplicate
// lifetime params for RPITs, and empty for TAITs.
match self
.tcx
.uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::FromFunction)
{
Ok(()) => {
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
// supported at all, so this is sound to do, but once we want to support them, you'll
// start seeing the error below.
// Collect opaque types nested within the associated type bounds of this opaque type.
// We use identity args here, because we already know that the opaque type uses
// only generic parameters, and thus substituting would not give us more information.
for (pred, span) in self
.tcx
.explicit_item_bounds(alias_ty.def_id)
.instantiate_identity_iter_copied()
{
trace!(?pred);
self.visit_spanned(span, pred);
}
}
Err(NotUniqueParam::NotParam(arg)) => {
self.tcx.dcx().emit_err(NotParam {
arg,
span: self.span(),
opaque_span: self.tcx.def_span(alias_ty.def_id),
});
}
Err(NotUniqueParam::DuplicateParam(arg)) => {
self.tcx.dcx().emit_err(DuplicateArg {
arg,
span: self.span(),
opaque_span: self.tcx.def_span(alias_ty.def_id),
});
}
}
}
}
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
@ -134,67 +197,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
if !self.seen.insert(alias_ty.def_id.expect_local()) {
return ControlFlow::Continue(());
}
// TAITs outside their defining scopes are ignored.
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
trace!(?origin);
match origin {
rustc_hir::OpaqueTyOrigin::FnReturn(_)
| rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
if !in_assoc_ty {
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
return ControlFlow::Continue(());
}
}
}
}
self.opaques.push(alias_ty.def_id.expect_local());
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
// Only check that the parent generics of the TAIT/RPIT are unique.
// the args owned by the opaque are going to always be duplicate
// lifetime params for RPITs, and empty for TAITs.
match self.tcx.uses_unique_generic_params(
&alias_ty.args[..parent_count],
CheckRegions::FromFunction,
) {
Ok(()) => {
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
// supported at all, so this is sound to do, but once we want to support them, you'll
// start seeing the error below.
// Collect opaque types nested within the associated type bounds of this opaque type.
// We use identity args here, because we already know that the opaque type uses
// only generic parameters, and thus substituting would not give us more information.
for (pred, span) in self
.tcx
.explicit_item_bounds(alias_ty.def_id)
.instantiate_identity_iter_copied()
{
trace!(?pred);
self.visit_spanned(span, pred);
}
}
Err(NotUniqueParam::NotParam(arg)) => {
self.tcx.dcx().emit_err(NotParam {
arg,
span: self.span(),
opaque_span: self.tcx.def_span(alias_ty.def_id),
});
}
Err(NotUniqueParam::DuplicateParam(arg)) => {
self.tcx.dcx().emit_err(DuplicateArg {
arg,
span: self.span(),
opaque_span: self.tcx.def_span(alias_ty.def_id),
});
}
}
self.visit_opaque_ty(alias_ty);
}
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
self.tcx
@ -272,6 +275,91 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
}
}
struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>);
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
let old = self.0.span;
self.0.span = Some(span);
value.visit_with(self);
self.0.span = old;
ControlFlow::Continue(())
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInAssocTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
self.0.visit_opaque_ty(alias_ty);
}
ty::Alias(ty::Projection, alias_ty) => {
// This avoids having to do normalization of `Self::AssocTy` by only
// supporting the case of a method defining opaque types from assoc types
// in the same impl block.
let parent_trait_ref = self
.0
.parent_trait_ref()
.expect("impl trait in assoc type collector used on non-assoc item");
// If the trait ref of the associated item and the impl differs,
// then we can't use the impl's identity substitutions below, so
// just skip.
if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref {
let parent = self.0.parent().expect("we should have a parent here");
for &assoc in self.0.tcx.associated_items(parent).in_definition_order() {
trace!(?assoc);
if assoc.trait_item_def_id != Some(alias_ty.def_id) {
continue;
}
// If the type is further specializable, then the type_of
// is not actually correct below.
if !assoc.defaultness(self.0.tcx).is_final() {
continue;
}
let impl_args = alias_ty.args.rebase_onto(
self.0.tcx,
parent_trait_ref.def_id,
ty::GenericArgs::identity_for_item(self.0.tcx, parent),
);
if check_args_compatible(self.0.tcx, assoc, impl_args) {
return self
.0
.tcx
.type_of(assoc.def_id)
.instantiate(self.0.tcx, impl_args)
.visit_with(self);
} else {
self.0.tcx.dcx().span_delayed_bug(
self.0.tcx.def_span(assoc.def_id),
"item had incorrect args",
);
}
}
}
}
_ => trace!(kind=?t.kind()),
}
ControlFlow::Continue(())
}
}
fn impl_trait_in_assoc_types_defined_by<'tcx>(
tcx: TyCtxt<'tcx>,
item: LocalDefId,
) -> &'tcx ty::List<LocalDefId> {
let mut collector = ImplTraitInAssocTypeCollector(OpaqueTypeCollector::new(tcx, item));
super::sig_types::walk_types(tcx, item, &mut collector);
tcx.mk_local_def_ids(&collector.0.opaques)
}
fn opaque_types_defined_by<'tcx>(
tcx: TyCtxt<'tcx>,
item: LocalDefId,
@ -321,5 +409,6 @@ fn opaque_types_defined_by<'tcx>(
}
pub(super) fn provide(providers: &mut Providers) {
*providers = Providers { opaque_types_defined_by, ..*providers };
*providers =
Providers { opaque_types_defined_by, impl_trait_in_assoc_types_defined_by, ..*providers };
}

View File

@ -357,6 +357,8 @@ define!("mir_unwind_resume",
define!("mir_storage_live", fn StorageLive<T>(local: T));
define!("mir_storage_dead", fn StorageDead<T>(local: T));
#[cfg(not(bootstrap))]
define!("mir_assume", fn Assume(operand: bool));
define!("mir_deinit", fn Deinit<T>(place: T));
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
define!("mir_len", fn Len<T>(place: T) -> usize);

View File

@ -1596,7 +1596,7 @@ pub(crate) mod builtin {
///
/// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(test, rustc_attrs)]
#[allow_internal_unstable(test, rustc_attrs, coverage_attribute)]
#[rustc_builtin_macro]
pub macro test($item:item) {
/* compiler built-in */
@ -1609,7 +1609,7 @@ pub(crate) mod builtin {
soft,
reason = "`bench` is a part of custom test frameworks which are unstable"
)]
#[allow_internal_unstable(test, rustc_attrs)]
#[allow_internal_unstable(test, rustc_attrs, coverage_attribute)]
#[rustc_builtin_macro]
pub macro bench($item:item) {
/* compiler built-in */

View File

@ -1,6 +1,9 @@
//! Definitions of integer that is known not to equal zero.
use crate::cmp::Ordering;
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::StructuralPartialEq;
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
use crate::str::FromStr;
@ -31,13 +34,6 @@ pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {
type NonZero;
}
#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
macro_rules! impl_zeroable_primitive {
($NonZero:ident ( $primitive:ty )) => {
#[unstable(
@ -71,6 +67,13 @@ impl_zeroable_primitive!(NonZeroI64(i64));
impl_zeroable_primitive!(NonZeroI128(i128));
impl_zeroable_primitive!(NonZeroIsize(isize));
#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
macro_rules! impl_nonzero_fmt {
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
$(
@ -128,7 +131,7 @@ macro_rules! nonzero_integer {
///
/// [null pointer optimization]: crate::option#representation
#[$stability]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Eq)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
@ -494,6 +497,96 @@ macro_rules! nonzero_integer {
}
}
#[$stability]
impl Clone for $Ty {
#[inline]
fn clone(&self) -> Self {
// SAFETY: The contained value is non-zero.
unsafe { Self(self.0) }
}
}
#[$stability]
impl PartialEq for $Ty {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
#[inline]
fn ne(&self, other: &Self) -> bool {
self.0 != other.0
}
}
#[unstable(feature = "structural_match", issue = "31434")]
impl StructuralPartialEq for $Ty {}
#[$stability]
impl PartialOrd for $Ty {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
#[inline]
fn lt(&self, other: &Self) -> bool {
self.0 < other.0
}
#[inline]
fn le(&self, other: &Self) -> bool {
self.0 <= other.0
}
#[inline]
fn gt(&self, other: &Self) -> bool {
self.0 > other.0
}
#[inline]
fn ge(&self, other: &Self) -> bool {
self.0 >= other.0
}
}
#[$stability]
impl Ord for $Ty {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
#[inline]
fn max(self, other: Self) -> Self {
// SAFETY: The maximum of two non-zero values is still non-zero.
unsafe { Self(self.0.max(other.0)) }
}
#[inline]
fn min(self, other: Self) -> Self {
// SAFETY: The minimum of two non-zero values is still non-zero.
unsafe { Self(self.0.min(other.0)) }
}
#[inline]
fn clamp(self, min: Self, max: Self) -> Self {
// SAFETY: A non-zero value clamped between two non-zero values is still non-zero.
unsafe { Self(self.0.clamp(min.0, max.0)) }
}
}
#[$stability]
impl Hash for $Ty {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.0.hash(state)
}
}
#[stable(feature = "from_nonzero", since = "1.31.0")]
impl From<$Ty> for $Int {
#[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]

View File

@ -108,15 +108,13 @@ impl Res {
Res::Primitive(_) => return Suggestion::Prefix("prim"),
Res::Def(kind, _) => kind,
};
if kind == DefKind::Macro(MacroKind::Bang) {
return Suggestion::Macro;
} else if kind == DefKind::Fn || kind == DefKind::AssocFn {
return Suggestion::Function;
} else if kind == DefKind::Field {
return Suggestion::RemoveDisambiguator;
}
let prefix = match kind {
DefKind::Fn | DefKind::AssocFn => return Suggestion::Function,
DefKind::Field => return Suggestion::RemoveDisambiguator,
DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro,
DefKind::Macro(MacroKind::Derive) => "derive",
DefKind::Struct => "struct",
DefKind::Enum => "enum",
DefKind::Trait => "trait",
@ -126,7 +124,6 @@ impl Res {
"const"
}
DefKind::Static(_) => "static",
DefKind::Macro(MacroKind::Derive) => "derive",
// Now handle things that don't have a specific disambiguator
_ => match kind
.ns()
@ -283,20 +280,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
debug!("looking for enum variant {path_str}");
let mut split = path_str.rsplitn(3, "::");
let variant_field_name = split
.next()
.map(|f| Symbol::intern(f))
.expect("fold_item should ensure link is non-empty");
let variant_name =
// we're not sure this is a variant at all, so use the full string
// If there's no second component, the link looks like `[path]`.
// So there's no partial res and we should say the whole link failed to resolve.
split.next().map(|f| Symbol::intern(f)).ok_or_else(no_res)?;
let path = split
.next()
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
// So there's no partial res.
.ok_or_else(no_res)?;
let variant_field_name = Symbol::intern(split.next().unwrap());
// We're not sure this is a variant at all, so use the full string.
// If there's no second component, the link looks like `[path]`.
// So there's no partial res and we should say the whole link failed to resolve.
let variant_name = Symbol::intern(split.next().ok_or_else(no_res)?);
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
// So there's no partial res.
let path = split.next().ok_or_else(no_res)?;
let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
match ty_res {
@ -447,41 +439,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}
// Try looking for methods and associated items.
let mut split = path_str.rsplitn(2, "::");
// NB: `split`'s first element is always defined, even if the delimiter was not present.
// NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`).
let item_str = split.next().unwrap();
let item_name = Symbol::intern(item_str);
let path_root = split
.next()
// NB: `path_root` could be empty when resolving in the root namespace (e.g. `::std`).
let (path_root, item_str) = path_str.rsplit_once("::").ok_or_else(|| {
// If there's no `::`, it's not an associated item.
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
.ok_or_else(|| {
debug!("found no `::`, assuming {item_name} was correctly not in scope");
UnresolvedPath {
item_id,
module_id,
partial_res: None,
unresolved: item_str.into(),
}
})?;
debug!("found no `::`, assuming {path_str} was correctly not in scope");
UnresolvedPath { item_id, module_id, partial_res: None, unresolved: path_str.into() }
})?;
let item_name = Symbol::intern(item_str);
// FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
// links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity
// error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all
// primitives.
match resolve_primitive(&path_root, TypeNS)
.or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
.and_then(|ty_res| {
let candidates = self
.resolve_associated_item(ty_res, item_name, ns, module_id)
match resolve_primitive(path_root, TypeNS)
.or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id))
.map(|ty_res| {
self.resolve_associated_item(ty_res, item_name, ns, module_id)
.into_iter()
.map(|(res, def_id)| (res, Some(def_id)))
.collect::<Vec<_>>();
if !candidates.is_empty() { Some(candidates) } else { None }
.collect::<Vec<_>>()
}) {
Some(r) => Ok(r),
None => {
Some(r) if !r.is_empty() => Ok(r),
_ => {
if ns == Namespace::ValueNS {
self.variant_field(path_str, item_id, module_id)
.map(|(res, def_id)| vec![(res, Some(def_id))])
@ -1263,7 +1243,7 @@ impl LinkCollector<'_, '_> {
self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item);
return None;
} else {
candidates = vec![candidates[0]];
candidates = vec![*candidate];
}
}
@ -1271,8 +1251,10 @@ impl LinkCollector<'_, '_> {
// and after removing duplicated kinds, only one remains, the `ambiguity_error` function
// won't emit an error. So at this point, we can just take the first candidate as it was
// the first retrieved and use it to generate the link.
if candidates.len() > 1 && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) {
candidates = vec![candidates[0]];
if let [candidate, _candidate2, ..] = *candidates
&& !ambiguity_error(self.cx, &diag, &key.path_str, &candidates)
{
candidates = vec![candidate];
}
if let &[(res, def_id)] = candidates.as_slice() {
@ -1322,12 +1304,11 @@ impl LinkCollector<'_, '_> {
let mut err = ResolutionFailure::NotResolved(err);
for other_ns in [TypeNS, ValueNS, MacroNS] {
if other_ns != expected_ns {
if let Ok(res) =
self.resolve(path_str, other_ns, item_id, module_id)
&& !res.is_empty()
if let Ok(&[res, ..]) =
self.resolve(path_str, other_ns, item_id, module_id).as_deref()
{
err = ResolutionFailure::WrongNamespace {
res: full_res(self.cx.tcx, res[0]),
res: full_res(self.cx.tcx, res),
expected_ns,
};
break;
@ -1748,7 +1729,6 @@ fn report_diagnostic(
lint.note(format!(
"the link appears in this line:\n\n{line}\n\
{indicator: <before$}{indicator:^<found$}",
line = line,
indicator = "",
before = md_range.start - last_new_line_offset,
found = md_range.len(),
@ -1807,18 +1787,13 @@ fn resolution_failure(
let item_id = *item_id;
let module_id = *module_id;
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
// FIXME: maybe use itertools `collect_tuple` instead?
fn split(path: &str) -> Option<(&str, &str)> {
let mut splitter = path.rsplitn(2, "::");
splitter.next().and_then(|right| splitter.next().map(|left| (left, right)))
}
// Check if _any_ parent of the path gets resolved.
// If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
let mut name = path_str;
'outer: loop {
let Some((start, end)) = split(name) else {
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
let Some((start, end)) = name.rsplit_once("::") else {
// avoid bug that marked [Quux::Z] as missing Z, not Quux
if partial_res.is_none() {
*unresolved = name.into();
@ -1829,8 +1804,8 @@ fn resolution_failure(
for ns in [TypeNS, ValueNS, MacroNS] {
if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
debug!("found partial_res={v_res:?}");
if !v_res.is_empty() {
*partial_res = Some(full_res(tcx, v_res[0]));
if let Some(&res) = v_res.first() {
*partial_res = Some(full_res(tcx, res));
*unresolved = end.into();
break 'outer;
}

View File

@ -0,0 +1,8 @@
Function name: bench::my_bench
Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39)

View File

@ -0,0 +1,9 @@
LL| |#![feature(test)]
LL| |// edition: 2021
LL| |// compile-flags: --test
LL| |
LL| |extern crate test;
LL| |
LL| |#[bench]
LL| 1|fn my_bench(_b: &mut test::Bencher) {}

8
tests/coverage/bench.rs Normal file
View File

@ -0,0 +1,8 @@
#![feature(test)]
// edition: 2021
// compile-flags: --test
extern crate test;
#[bench]
fn my_bench(_b: &mut test::Bencher) {}

View File

@ -6,14 +6,6 @@ Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16)
Function name: test_harness::my_test::{closure#0}
Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 01, 00, 08]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 8)
Function name: test_harness::unused (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f]
Number of files: 1

View File

@ -6,6 +6,6 @@
LL| |#[allow(dead_code)]
LL| 0|fn unused() {}
LL| |
LL| 1|#[test]
LL| |#[test]
LL| 1|fn my_test() {}

View File

@ -0,0 +1,10 @@
// MIR for `assume_constant` after built
fn assume_constant() -> () {
let mut _0: ();
bb0: {
assume(const true);
return;
}
}

View File

@ -0,0 +1,10 @@
// MIR for `assume_local` after built
fn assume_local(_1: bool) -> () {
let mut _0: ();
bb0: {
assume(_1);
return;
}
}

View File

@ -0,0 +1,10 @@
// MIR for `assume_place` after built
fn assume_place(_1: (bool, u8)) -> () {
let mut _0: ();
bb0: {
assume((_1.0: bool));
return;
}
}

View File

@ -0,0 +1,44 @@
// skip-filecheck
#![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
// EMIT_MIR assume.assume_local.built.after.mir
#[custom_mir(dialect = "built")]
fn assume_local(x: bool) {
mir!(
{
Assume(x);
Return()
}
)
}
// EMIT_MIR assume.assume_place.built.after.mir
#[custom_mir(dialect = "built")]
fn assume_place(p: (bool, u8)) {
mir!(
{
Assume(p.0);
Return()
}
)
}
// EMIT_MIR assume.assume_constant.built.after.mir
#[custom_mir(dialect = "built")]
fn assume_constant() {
mir!(
{
Assume(true);
Return()
}
)
}
fn main() {
assume_local(true);
assume_place((true, 50));
assume_constant();
}

View File

@ -0,0 +1,39 @@
- // MIR for `assume` before JumpThreading
+ // MIR for `assume` after JumpThreading
fn assume(_1: u8, _2: bool) -> u8 {
let mut _0: u8;
bb0: {
switchInt(_1) -> [7: bb1, otherwise: bb2];
}
bb1: {
assume(_2);
- goto -> bb3;
+ goto -> bb6;
}
bb2: {
goto -> bb3;
}
bb3: {
switchInt(_2) -> [0: bb4, otherwise: bb5];
}
bb4: {
_0 = const 4_u8;
return;
}
bb5: {
_0 = const 5_u8;
return;
+ }
+
+ bb6: {
+ goto -> bb5;
}
}

View File

@ -0,0 +1,39 @@
- // MIR for `assume` before JumpThreading
+ // MIR for `assume` after JumpThreading
fn assume(_1: u8, _2: bool) -> u8 {
let mut _0: u8;
bb0: {
switchInt(_1) -> [7: bb1, otherwise: bb2];
}
bb1: {
assume(_2);
- goto -> bb3;
+ goto -> bb6;
}
bb2: {
goto -> bb3;
}
bb3: {
switchInt(_2) -> [0: bb4, otherwise: bb5];
}
bb4: {
_0 = const 4_u8;
return;
}
bb5: {
_0 = const 5_u8;
return;
+ }
+
+ bb6: {
+ goto -> bb5;
}
}

View File

@ -468,6 +468,52 @@ fn aggregate(x: u8) -> u8 {
}
}
/// Verify that we can leverage the existence of an `Assume` terminator.
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn assume(a: u8, b: bool) -> u8 {
// CHECK-LABEL: fn assume(
mir!(
{
// CHECK: bb0: {
// CHECK-NEXT: switchInt(_1) -> [7: bb1, otherwise: bb2]
match a { 7 => bb1, _ => bb2 }
}
bb1 = {
// CHECK: bb1: {
// CHECK-NEXT: assume(_2);
// CHECK-NEXT: goto -> bb6;
Assume(b);
Goto(bb3)
}
bb2 = {
// CHECK: bb2: {
// CHECK-NEXT: goto -> bb3;
Goto(bb3)
}
bb3 = {
// CHECK: bb3: {
// CHECK-NEXT: switchInt(_2) -> [0: bb4, otherwise: bb5];
match b { false => bb4, _ => bb5 }
}
bb4 = {
// CHECK: bb4: {
// CHECK-NEXT: _0 = const 4_u8;
// CHECK-NEXT: return;
RET = 4;
Return()
}
bb5 = {
// CHECK: bb5: {
// CHECK-NEXT: _0 = const 5_u8;
// CHECK-NEXT: return;
RET = 5;
Return()
}
// CHECK: bb6: {
// CHECK-NEXT: goto -> bb5;
)
}
fn main() {
// CHECK-LABEL: fn main(
too_complex(Ok(0));
@ -481,6 +527,7 @@ fn main() {
renumbered_bb(true);
disappearing_bb(7);
aggregate(7);
assume(7, false);
}
// EMIT_MIR jump_threading.too_complex.JumpThreading.diff
@ -494,3 +541,4 @@ fn main() {
// EMIT_MIR jump_threading.renumbered_bb.JumpThreading.diff
// EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff
// EMIT_MIR jump_threading.aggregate.JumpThreading.diff
// EMIT_MIR jump_threading.assume.JumpThreading.diff

View File

@ -28,7 +28,8 @@ pub const m_test: test::TestDescAndFn =
should_panic: test::ShouldPanic::No,
test_type: test::TestType::Unknown,
},
testfn: test::StaticTestFn(|| test::assert_test_result(m_test())),
testfn: test::StaticTestFn(#[coverage(off)] ||
test::assert_test_result(m_test())),
};
fn m_test() {}
@ -51,7 +52,8 @@ pub const z_test: test::TestDescAndFn =
should_panic: test::ShouldPanic::No,
test_type: test::TestType::Unknown,
},
testfn: test::StaticTestFn(|| test::assert_test_result(z_test())),
testfn: test::StaticTestFn(#[coverage(off)] ||
test::assert_test_result(z_test())),
};
#[ignore = "not yet implemented"]
fn z_test() {}
@ -75,7 +77,8 @@ pub const a_test: test::TestDescAndFn =
should_panic: test::ShouldPanic::No,
test_type: test::TestType::Unknown,
},
testfn: test::StaticTestFn(|| test::assert_test_result(a_test())),
testfn: test::StaticTestFn(#[coverage(off)] ||
test::assert_test_result(a_test())),
};
fn a_test() {}
#[rustc_main]

View File

@ -0,0 +1,13 @@
use std::convert::identity;
fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
//~^ ERROR concrete type differs from previous defining opaque type use
let true = n else { loop {} };
let _ = || {
let _ = identity::<&'a ()>(test(false));
//~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
};
loop {}
}
fn main() {}

View File

@ -0,0 +1,26 @@
error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
--> $DIR/early_bound.rs:7:17
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| -- --------------- opaque type defined here
| |
| hidden type `&'a ()` captures the lifetime `'a` as defined here
...
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: concrete type differs from previous defining opaque type use
--> $DIR/early_bound.rs:3:29
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| ^^^^^^^^^^^^^^^ expected `&()`, got `()`
|
note: previous use here
--> $DIR/early_bound.rs:7:36
|
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -6,4 +6,5 @@ extern crate ambiguous_1;
fn main() {
ambiguous_1::id();
//^ FIXME: `id` should be identified as an ambiguous item.
}

View File

@ -5,5 +5,5 @@ extern crate ambiguous_4_extern;
fn main() {
ambiguous_4_extern::id();
// `warning_ambiguous` had been lost at metadata.
//^ FIXME: `id` should be identified as an ambiguous item.
}

View File

@ -0,0 +1,10 @@
mod a {
pub type C = i8;
}
mod b {
pub type C = i16;
}
pub use a::*;
pub use b::*;

View File

@ -0,0 +1,17 @@
macro_rules! m {
() => {
pub fn max() {}
pub(crate) mod max {}
};
}
mod d {
m! {}
}
mod e {
pub type max = i32;
}
pub use self::d::*;
pub use self::e::*;

View File

@ -0,0 +1,16 @@
mod gio {
pub trait SettingsExt {
fn abc(&self) {}
}
impl<T> SettingsExt for T {}
}
mod gtk {
pub trait SettingsExt {
fn efg(&self) {}
}
impl<T> SettingsExt for T {}
}
pub use gtk::*;
pub use gio::*;

View File

@ -0,0 +1,10 @@
mod a {
pub type Result<T> = std::result::Result<T, ()>;
}
mod b {
pub type Result<T> = std::result::Result<T, ()>;
}
pub use a::*;
pub use b::*;

View File

@ -0,0 +1 @@
pub struct Url;

View File

@ -0,0 +1,13 @@
// edition: 2018
// aux-build: issue-114682-5-extern-1.rs
// compile-flags: --extern issue_114682_5_extern_1
pub mod p {
pub use crate::types::*;
pub use crate::*;
}
mod types {
pub mod issue_114682_5_extern_1 {}
}
pub use issue_114682_5_extern_1;

View File

@ -0,0 +1,9 @@
mod a {
pub fn log() {}
}
mod b {
pub fn log() {}
}
pub use self::a::*;
pub use self::b::*;

View File

@ -12,5 +12,7 @@ mod s {
use s::*;
use extern_with_ambiguous_2_extern::*;
use error::*;
//^ FIXME: An ambiguity error should be thrown for `error`,
// as there is ambiguity present within `extern-with-ambiguous-2-extern.rs`.
fn main() {}

View File

@ -13,5 +13,7 @@ mod s {
use s::*;
use extern_with_ambiguous_3_extern::*;
use error::*;
//^ FIXME: An ambiguity error should be thrown for `error`,
// as there is ambiguity present within `extern-with-ambiguous-3-extern.rs`.
fn main() {}

View File

@ -4,5 +4,9 @@ extern crate glob_conflict;
fn main() {
glob_conflict::f(); //~ ERROR cannot find function `f` in crate `glob_conflict`
//^ FIXME: `glob_conflict::f` should raise an
// ambiguity error instead of a not found error.
glob_conflict::glob::f(); //~ ERROR cannot find function `f` in module `glob_conflict::glob`
//^ FIXME: `glob_conflict::glob::f` should raise an
// ambiguity error instead of a not found error.
}

View File

@ -1,11 +1,11 @@
error[E0425]: cannot find function `f` in crate `glob_conflict`
--> $DIR/glob-conflict-cross-crate.rs:6:20
--> $DIR/glob-conflict-cross-crate-1.rs:6:20
|
LL | glob_conflict::f();
| ^ not found in `glob_conflict`
error[E0425]: cannot find function `f` in module `glob_conflict::glob`
--> $DIR/glob-conflict-cross-crate.rs:7:26
--> $DIR/glob-conflict-cross-crate-1.rs:9:26
|
LL | glob_conflict::glob::f();
| ^ not found in `glob_conflict::glob`

View File

@ -0,0 +1,10 @@
// aux-build:glob-conflict-cross-crate-2-extern.rs
extern crate glob_conflict_cross_crate_2_extern;
use glob_conflict_cross_crate_2_extern::*;
fn main() {
let _a: C = 1; //~ ERROR cannot find type `C` in this scope
//^ FIXME: `C` should be identified as an ambiguous item.
}

View File

@ -0,0 +1,9 @@
error[E0412]: cannot find type `C` in this scope
--> $DIR/glob-conflict-cross-crate-2.rs:8:13
|
LL | let _a: C = 1;
| ^ not found in this scope
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0412`.

View File

@ -0,0 +1,16 @@
// check-pass
// aux-build:glob-conflict-cross-crate-2-extern.rs
extern crate glob_conflict_cross_crate_2_extern;
mod a {
pub type C = i32;
}
use glob_conflict_cross_crate_2_extern::*;
use a::*;
fn main() {
let _a: C = 1;
//^ FIXME: `C` should be identified as an ambiguous item.
}

View File

@ -0,0 +1,25 @@
// https://github.com/rust-lang/rust/pull/114682#discussion_r1420534109
#![feature(decl_macro)]
macro_rules! mac {
() => {
pub macro A() {
println!("non import")
}
}
}
mod m {
pub macro A() {
println!("import")
}
}
pub use m::*;
mac!();
fn main() {
A!();
//~^ ERROR `A` is ambiguous
}

View File

@ -0,0 +1,28 @@
error[E0659]: `A` is ambiguous
--> $DIR/issue-114682-1.rs:23:5
|
LL | A!();
| ^ ambiguous name
|
= note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `A` could refer to the macro defined here
--> $DIR/issue-114682-1.rs:7:9
|
LL | / pub macro A() {
LL | | println!("non import")
LL | | }
| |_________^
...
LL | mac!();
| ------ in this macro invocation
note: `A` could also refer to the macro imported here
--> $DIR/issue-114682-1.rs:19:9
|
LL | pub use m::*;
| ^^^^
= help: consider adding an explicit import of `A` to disambiguate
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0659`.

View File

@ -0,0 +1,19 @@
// aux-build: issue-114682-2-extern.rs
// https://github.com/rust-lang/rust/pull/114682#issuecomment-1879998900
extern crate issue_114682_2_extern;
use issue_114682_2_extern::max;
type A = issue_114682_2_extern::max;
//~^ ERROR: expected type, found function `issue_114682_2_extern::max`
// FIXME:
// The above error was emitted due to `(Mod(issue_114682_2_extern), Namespace(Type), Ident(max))`
// being identified as an ambiguous item.
// However, there are two points worth discussing:
// First, should this ambiguous item be omitted considering the maximum visibility
// of `issue_114682_2_extern::m::max` in the type namespace is only within the extern crate.
// Second, if we retain the ambiguous item of the extern crate, should it be treated
// as an ambiguous item within the local crate for the same reasoning?
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0573]: expected type, found function `issue_114682_2_extern::max`
--> $DIR/issue-114682-2.rs:8:10
|
LL | type A = issue_114682_2_extern::max;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0573`.

View File

@ -0,0 +1,24 @@
// check-pass
// aux-build: issue-114682-3-extern.rs
// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880625909
extern crate issue_114682_3_extern;
use issue_114682_3_extern::*;
mod auto {
pub trait SettingsExt {
fn ext(&self) {}
}
impl<T> SettingsExt for T {}
}
pub use self::auto::*;
fn main() {
let a: u8 = 1;
a.ext();
//^ FIXME: it should report `ext` not found because `SettingsExt`
// is an ambiguous item in `issue-114682-3-extern.rs`.
}

View File

@ -0,0 +1,13 @@
// check-pass
// aux-build: issue-114682-4-extern.rs
// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441
extern crate issue_114682_4_extern;
use issue_114682_4_extern::*;
fn a() -> Result<i32, ()> { // FIXME: `Result` should be identified as an ambiguous item.
Ok(1)
}
fn main() {}

View File

@ -0,0 +1,15 @@
// check-pass
// edition: 2018
// aux-build: issue-114682-5-extern-1.rs
// aux-build: issue-114682-5-extern-2.rs
// compile-flags: --extern issue_114682_5_extern_1
// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441
extern crate issue_114682_5_extern_2;
use issue_114682_5_extern_2::p::*;
use issue_114682_5_extern_1::Url;
// FIXME: The `issue_114682_5_extern_1` should be considered an ambiguous item,
// as it has already been recognized as ambiguous in `issue_114682_5_extern_2`.
fn main() {}

View File

@ -0,0 +1,13 @@
// check-pass
// aux-build: issue-114682-6-extern.rs
// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441
extern crate issue_114682_6_extern;
use issue_114682_6_extern::*;
fn main() {
let log = 2;
//^ `log` should be identified as an ambiguous item.
let _ = log;
}

View File

@ -4,7 +4,7 @@ fn invalid_emoji_usages() {
let wireless🛜 = "basic emoji"; //~ ERROR: identifiers cannot contain emoji
// FIXME
let key1 = "keycap sequence"; //~ ERROR: unknown start of token
//~^ WARN: identifier contains uncommon Unicode codepoints
//~^ WARN: identifier contains an uncommon Unicode codepoint
let flag🇺🇳 = "flag sequence"; //~ ERROR: identifiers cannot contain emoji
let wales🏴 = "tag sequence"; //~ ERROR: identifiers cannot contain emoji
let folded🙏🏿 = "modifier sequence"; //~ ERROR: identifiers cannot contain emoji

View File

@ -40,7 +40,7 @@ error: identifiers cannot contain emoji: `folded🙏🏿`
LL | let folded🙏🏿 = "modifier sequence";
| ^^^^^^^^^^
warning: identifier contains uncommon Unicode codepoints
warning: identifier contains an uncommon Unicode codepoint: '\u{fe0f}'
--> $DIR/lex-emoji-identifiers.rs:6:9
|
LL | let key1⃣ = "keycap sequence";

View File

@ -1,9 +1,9 @@
#![deny(uncommon_codepoints)]
const µ: f64 = 0.000001; //~ ERROR identifier contains uncommon Unicode codepoints
const µ: f64 = 0.000001; //~ ERROR identifier contains an uncommon Unicode codepoint
//~| WARNING should have an upper case name
fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
fn dijkstra() {} //~ ERROR identifier contains an uncommon Unicode codepoint
fn main() {
let = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints

View File

@ -1,4 +1,4 @@
error: identifier contains uncommon Unicode codepoints
error: identifier contains an uncommon Unicode codepoint: 'µ'
--> $DIR/lint-uncommon-codepoints.rs:3:7
|
LL | const µ: f64 = 0.000001;
@ -10,13 +10,13 @@ note: the lint level is defined here
LL | #![deny(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: identifier contains uncommon Unicode codepoints
error: identifier contains an uncommon Unicode codepoint: 'ij'
--> $DIR/lint-uncommon-codepoints.rs:6:4
|
LL | fn dijkstra() {}
| ^^^^^^^
error: identifier contains uncommon Unicode codepoints
error: identifier contains uncommon Unicode codepoints: 'ㇻ', 'ㇲ', and 'ㇳ'
--> $DIR/lint-uncommon-codepoints.rs:9:9
|
LL | let ㇻㇲㇳ = "rust";

View File

@ -1,9 +1,8 @@
//! This test shows that we can even follow projections
//! into associated types of the same impl if they are
//! indirectly mentioned in a struct field.
//! This test shows that we do not treat opaque types
//! as defined by a method if the opaque type is
//! only indirectly mentioned in a struct field.
#![feature(impl_trait_in_assoc_type)]
// check-pass
struct Bar;
@ -16,6 +15,7 @@ impl Trait for Bar {
type Assoc = impl std::fmt::Debug;
fn foo() -> Foo {
Foo { field: () }
//~^ ERROR: item constrains opaque type that is not in its signature
}
}

View File

@ -0,0 +1,15 @@
error: item constrains opaque type that is not in its signature
--> $DIR/hidden_behind_struct_field2.rs:17:22
|
LL | Foo { field: () }
| ^^
|
= note: this item must mention the opaque type in its signature in order to be able to register hidden types
note: this item must mention the opaque type in its signature in order to be able to register hidden types
--> $DIR/hidden_behind_struct_field2.rs:16:8
|
LL | fn foo() -> Foo {
| ^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,38 @@
//! Check that we cannot instantiate a hidden type in the body
//! of an assoc fn or const unless mentioned in the signature.
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
fn foo();
fn bar() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
fn foo() {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
}
fn bar() -> Self::Assoc {
""
}
}
trait Trait2: Sized {
type Assoc;
const FOO: ();
fn bar() -> Self::Assoc;
}
impl Trait2 for () {
type Assoc = impl std::fmt::Debug;
const FOO: () = {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
};
fn bar() -> Self::Assoc {
""
}
}
fn main() {}

View File

@ -0,0 +1,41 @@
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:15:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | fn foo() {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait>::Assoc`
found type `{integer}`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:14:8
|
LL | fn foo() {
| ^^^
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:31:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | const FOO: () = {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait2>::Assoc`
found type `{integer}`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:30:11
|
LL | const FOO: () = {
| ^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,22 @@
//! Check that we cannot instantiate a hidden type from another assoc type.
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
type Foo;
fn foo() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
type Foo = [(); {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
3
}];
fn foo() -> Self::Assoc {
""
}
}
fn main() {}

View File

@ -0,0 +1,17 @@
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait2.rs:14:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | type Foo = [(); {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait>::Assoc`
found type `{integer}`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,38 @@
//! Check that non-defining assoc items can use the opaque type
//! opaquely.
// check-pass
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
fn foo();
fn bar() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
fn foo() {
let x: Self::Assoc = Self::bar();
}
fn bar() -> Self::Assoc {
""
}
}
trait Trait2: Sized {
type Assoc;
const FOO: ();
const BAR: Self::Assoc;
}
impl Trait2 for () {
type Assoc = impl Copy;
const FOO: () = {
let x: Self::Assoc = Self::BAR;
};
const BAR: Self::Assoc = "";
}
fn main() {}

View File

@ -0,0 +1,17 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc<'a, 'b>;
fn bar<'a: 'a, 'b: 'b>(_: &'a ()) -> Self::Assoc<'a, 'b>;
}
impl Foo for () {
type Assoc<'a, 'b> = impl Sized;
fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> {
let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x };
//~^ ERROR `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds
x
}
}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0700]: hidden type for `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds
--> $DIR/in-assoc-ty-early-bound.rs:11:60
|
LL | type Assoc<'a, 'b> = impl Sized;
| ---------- opaque type defined here
LL | fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> {
| -- hidden type `&'a ()` captures the lifetime `'a` as defined here
LL | let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x };
| ^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -0,0 +1,21 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc<'a>;
fn bar<'a: 'a>();
}
impl Foo for () {
type Assoc<'a> = impl Sized; //~ ERROR unconstrained opaque type
fn bar<'a: 'a>()
where
Self::Assoc<'a>:,
{
let _ = |x: &'a ()| {
let _: Self::Assoc<'a> = x;
//~^ ERROR `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bound
};
}
}
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0700]: hidden type for `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bounds
--> $DIR/in-assoc-ty-early-bound2.rs:15:20
|
LL | type Assoc<'a> = impl Sized;
| ---------- opaque type defined here
LL | fn bar<'a: 'a>()
| -- hidden type `&'a ()` captures the lifetime `'a` as defined here
...
LL | let _: Self::Assoc<'a> = x;
| ^^^^^^^^^^^^^^^
error: unconstrained opaque type
--> $DIR/in-assoc-ty-early-bound2.rs:9:22
|
LL | type Assoc<'a> = impl Sized;
| ^^^^^^^^^^
|
= note: `Assoc` must be used in combination with a concrete type within the same impl
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -0,0 +1,23 @@
error[E0308]: mismatched types
--> $DIR/itiat-allow-nested-closures.rs:21:22
|
LL | type Assoc = impl Sized;
| ---------- the found opaque type
...
LL | let _: i32 = closure();
| --- ^^^^^^^^^ expected `i32`, found opaque type
| |
| expected due to this
error[E0308]: mismatched types
--> $DIR/itiat-allow-nested-closures.rs:22:9
|
LL | fn bar() -> Self::Assoc {
| ----------- expected `()` because of return type
...
LL | 1i32
| ^^^^ expected `()`, found `i32`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,26 @@
#![feature(impl_trait_in_assoc_type)]
// revisions: ok bad
// [ok] check-pass
trait Foo {
type Assoc;
fn bar() -> Self::Assoc;
}
impl Foo for () {
type Assoc = impl Sized;
fn bar() -> Self::Assoc {
let closure = || -> Self::Assoc {
#[cfg(ok)]
let x: Self::Assoc = 42_i32;
#[cfg(bad)]
let x: Self::Assoc = ();
x
};
let _: i32 = closure(); //[bad]~ ERROR mismatched types
1i32 //[bad]~ ERROR mismatched types
}
}
fn main() {}

View File

@ -0,0 +1,20 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc;
fn bar() -> Self::Assoc;
}
impl Foo for () {
type Assoc = impl Sized;
fn bar() -> Self::Assoc {
fn foo() -> <() as Foo>::Assoc {
let x: <() as Foo>::Assoc = 42_i32; //~ ERROR mismatched types
x
};
let _: i32 = foo();
1i32
}
}
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0308]: mismatched types
--> $DIR/itiat-forbid-nested-items.rs:12:41
|
LL | type Assoc = impl Sized;
| ---------- the expected opaque type
...
LL | let x: <() as Foo>::Assoc = 42_i32;
| ------------------ ^^^^^^ expected opaque type, found `i32`
| |
| expected due to this
|
= note: expected opaque type `<() as Foo>::Assoc`
found type `i32`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/itiat-forbid-nested-items.rs:11:12
|
LL | fn foo() -> <() as Foo>::Assoc {
| ^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,32 @@
// run-rustfix
trait Trait {}
struct Struct;
impl Trait for Struct {}
fn foo() -> Box<dyn Trait> {
Box::new(Struct)
}
fn bar() -> impl Trait {
Struct
}
fn main() {
let _ = if true {
Box::new(Struct)
} else {
foo() //~ ERROR E0308
};
let _ = if true {
foo()
} else {
Box::new(Struct) //~ ERROR E0308
};
let _ = if true {
Box::new(Struct) as Box<dyn Trait>
} else {
Box::new(bar()) //~ ERROR E0308
};
let _ = if true {
Box::new(bar()) as Box<dyn Trait>
} else {
Box::new(Struct) //~ ERROR E0308
};
}

View File

@ -0,0 +1,32 @@
// run-rustfix
trait Trait {}
struct Struct;
impl Trait for Struct {}
fn foo() -> Box<dyn Trait> {
Box::new(Struct)
}
fn bar() -> impl Trait {
Struct
}
fn main() {
let _ = if true {
Struct
} else {
foo() //~ ERROR E0308
};
let _ = if true {
foo()
} else {
Struct //~ ERROR E0308
};
let _ = if true {
Struct
} else {
bar() //~ ERROR E0308
};
let _ = if true {
bar()
} else {
Struct //~ ERROR E0308
};
}

View File

@ -0,0 +1,94 @@
error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-box-on-divergent-if-else-arms.rs:15:9
|
LL | let _ = if true {
| _____________-
LL | | Struct
| | ------ expected because of this
LL | | } else {
LL | | foo()
| | ^^^^^ expected `Struct`, found `Box<dyn Trait>`
LL | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected struct `Struct`
found struct `Box<dyn Trait>`
help: `Struct` implements `Trait` so you can box it to coerce to the trait object `Box<dyn Trait>`
|
LL | Box::new(Struct)
| +++++++++ +
error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-box-on-divergent-if-else-arms.rs:20:9
|
LL | let _ = if true {
| _____________-
LL | | foo()
| | ----- expected because of this
LL | | } else {
LL | | Struct
| | ^^^^^^ expected `Box<dyn Trait>`, found `Struct`
LL | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected struct `Box<dyn Trait>`
found struct `Struct`
= note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
help: store this in the heap by calling `Box::new`
|
LL | Box::new(Struct)
| +++++++++ +
error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-box-on-divergent-if-else-arms.rs:25:9
|
LL | fn bar() -> impl Trait {
| ---------- the found opaque type
...
LL | let _ = if true {
| _____________-
LL | | Struct
| | ------ expected because of this
LL | | } else {
LL | | bar()
| | ^^^^^ expected `Struct`, found opaque type
LL | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected struct `Struct`
found opaque type `impl Trait`
help: `Struct` implements `Trait` so you can box both arms and coerce to the trait object `Box<dyn Trait>`
|
LL ~ Box::new(Struct) as Box<dyn Trait>
LL | } else {
LL ~ Box::new(bar())
|
error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-box-on-divergent-if-else-arms.rs:30:9
|
LL | fn bar() -> impl Trait {
| ---------- the expected opaque type
...
LL | let _ = if true {
| _____________-
LL | | bar()
| | ----- expected because of this
LL | | } else {
LL | | Struct
| | ^^^^^^ expected opaque type, found `Struct`
LL | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected opaque type `impl Trait`
found struct `Struct`
help: `Struct` implements `Trait` so you can box both arms and coerce to the trait object `Box<dyn Trait>`
|
LL ~ Box::new(bar()) as Box<dyn Trait>
LL | } else {
LL ~ Box::new(Struct)
|
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.