mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
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:
commit
0b7730105f
@ -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)]
|
||||
|
@ -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(
|
||||
), // )
|
||||
],
|
||||
), // }
|
||||
), // )
|
||||
)), // )
|
||||
],
|
||||
)
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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>) {
|
||||
|
@ -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)
|
||||
|
@ -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!(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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`.
|
||||
|
@ -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(
|
||||
|
@ -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])?)))
|
||||
},
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -1028,6 +1028,7 @@ symbols! {
|
||||
minnumf32,
|
||||
minnumf64,
|
||||
mips_target_feature,
|
||||
mir_assume,
|
||||
mir_basic_block,
|
||||
mir_call,
|
||||
mir_cast_transmute,
|
||||
|
@ -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)),
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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), "`")]
|
||||
|
@ -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;
|
||||
}
|
||||
|
8
tests/coverage/bench.cov-map
Normal file
8
tests/coverage/bench.cov-map
Normal 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)
|
||||
|
9
tests/coverage/bench.coverage
Normal file
9
tests/coverage/bench.coverage
Normal 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
8
tests/coverage/bench.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![feature(test)]
|
||||
// edition: 2021
|
||||
// compile-flags: --test
|
||||
|
||||
extern crate test;
|
||||
|
||||
#[bench]
|
||||
fn my_bench(_b: &mut test::Bencher) {}
|
@ -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
|
||||
|
@ -6,6 +6,6 @@
|
||||
LL| |#[allow(dead_code)]
|
||||
LL| 0|fn unused() {}
|
||||
LL| |
|
||||
LL| 1|#[test]
|
||||
LL| |#[test]
|
||||
LL| 1|fn my_test() {}
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
// MIR for `assume_constant` after built
|
||||
|
||||
fn assume_constant() -> () {
|
||||
let mut _0: ();
|
||||
|
||||
bb0: {
|
||||
assume(const true);
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// MIR for `assume_local` after built
|
||||
|
||||
fn assume_local(_1: bool) -> () {
|
||||
let mut _0: ();
|
||||
|
||||
bb0: {
|
||||
assume(_1);
|
||||
return;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
44
tests/mir-opt/building/custom/assume.rs
Normal file
44
tests/mir-opt/building/custom/assume.rs
Normal 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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
13
tests/ui/impl-trait/rpit/early_bound.rs
Normal file
13
tests/ui/impl-trait/rpit/early_bound.rs
Normal 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() {}
|
26
tests/ui/impl-trait/rpit/early_bound.stderr
Normal file
26
tests/ui/impl-trait/rpit/early_bound.stderr
Normal 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`.
|
@ -6,4 +6,5 @@ extern crate ambiguous_1;
|
||||
|
||||
fn main() {
|
||||
ambiguous_1::id();
|
||||
//^ FIXME: `id` should be identified as an ambiguous item.
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
mod a {
|
||||
pub type C = i8;
|
||||
}
|
||||
|
||||
mod b {
|
||||
pub type C = i16;
|
||||
}
|
||||
|
||||
pub use a::*;
|
||||
pub use b::*;
|
17
tests/ui/imports/auxiliary/issue-114682-2-extern.rs
Normal file
17
tests/ui/imports/auxiliary/issue-114682-2-extern.rs
Normal 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::*;
|
16
tests/ui/imports/auxiliary/issue-114682-3-extern.rs
Normal file
16
tests/ui/imports/auxiliary/issue-114682-3-extern.rs
Normal 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::*;
|
10
tests/ui/imports/auxiliary/issue-114682-4-extern.rs
Normal file
10
tests/ui/imports/auxiliary/issue-114682-4-extern.rs
Normal 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::*;
|
1
tests/ui/imports/auxiliary/issue-114682-5-extern-1.rs
Normal file
1
tests/ui/imports/auxiliary/issue-114682-5-extern-1.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct Url;
|
13
tests/ui/imports/auxiliary/issue-114682-5-extern-2.rs
Normal file
13
tests/ui/imports/auxiliary/issue-114682-5-extern-2.rs
Normal 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;
|
9
tests/ui/imports/auxiliary/issue-114682-6-extern.rs
Normal file
9
tests/ui/imports/auxiliary/issue-114682-6-extern.rs
Normal file
@ -0,0 +1,9 @@
|
||||
mod a {
|
||||
pub fn log() {}
|
||||
}
|
||||
mod b {
|
||||
pub fn log() {}
|
||||
}
|
||||
|
||||
pub use self::a::*;
|
||||
pub use self::b::*;
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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.
|
||||
}
|
@ -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`
|
10
tests/ui/imports/glob-conflict-cross-crate-2.rs
Normal file
10
tests/ui/imports/glob-conflict-cross-crate-2.rs
Normal 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.
|
||||
}
|
9
tests/ui/imports/glob-conflict-cross-crate-2.stderr
Normal file
9
tests/ui/imports/glob-conflict-cross-crate-2.stderr
Normal 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`.
|
16
tests/ui/imports/glob-conflict-cross-crate-3.rs
Normal file
16
tests/ui/imports/glob-conflict-cross-crate-3.rs
Normal 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.
|
||||
}
|
25
tests/ui/imports/issue-114682-1.rs
Normal file
25
tests/ui/imports/issue-114682-1.rs
Normal 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
|
||||
}
|
28
tests/ui/imports/issue-114682-1.stderr
Normal file
28
tests/ui/imports/issue-114682-1.stderr
Normal 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`.
|
19
tests/ui/imports/issue-114682-2.rs
Normal file
19
tests/ui/imports/issue-114682-2.rs
Normal 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() {}
|
9
tests/ui/imports/issue-114682-2.stderr
Normal file
9
tests/ui/imports/issue-114682-2.stderr
Normal 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`.
|
24
tests/ui/imports/issue-114682-3.rs
Normal file
24
tests/ui/imports/issue-114682-3.rs
Normal 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`.
|
||||
}
|
13
tests/ui/imports/issue-114682-4.rs
Normal file
13
tests/ui/imports/issue-114682-4.rs
Normal 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() {}
|
15
tests/ui/imports/issue-114682-5.rs
Normal file
15
tests/ui/imports/issue-114682-5.rs
Normal 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() {}
|
13
tests/ui/imports/issue-114682-6.rs
Normal file
13
tests/ui/imports/issue-114682-6.rs
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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() {}
|
@ -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`.
|
@ -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() {}
|
17
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs
Normal file
17
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs
Normal 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() {}
|
@ -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`.
|
21
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs
Normal file
21
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs
Normal 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() {}
|
@ -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`.
|
@ -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`.
|
@ -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() {}
|
20
tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs
Normal file
20
tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs
Normal 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() {}
|
@ -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`.
|
32
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed
Normal file
32
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed
Normal 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
|
||||
};
|
||||
}
|
32
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs
Normal file
32
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs
Normal 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
|
||||
};
|
||||
}
|
94
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr
Normal file
94
tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user