mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Auto merge of #107919 - Dylan-DPC:rollup-fkl9swa, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #105019 (Add parentheses properly for borrowing suggestion) - #106001 (Stop at the first `NULL` argument when iterating `argv`) - #107098 (Suggest function call on pattern type mismatch) - #107490 (rustdoc: remove inconsistently-present sidebar tooltips) - #107855 (Add a couple random projection tests for new solver) - #107857 (Add ui test for implementation on projection) - #107878 (Clarify `new_size` for realloc means bytes) - #107888 (revert #107074, add regression test) - #107900 (Zero the `REPARSE_MOUNTPOINT_DATA_BUFFER` header) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
71f6675de1
@ -13,7 +13,7 @@ use rustc_middle::mir::{
|
||||
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
||||
TerminatorKind, UnOp, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||
@ -231,6 +231,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We sometimes have to use `defining_opaque_types` for subtyping
|
||||
// to succeed here and figuring out how exactly that should work
|
||||
// is annoying. It is harmless enough to just not validate anything
|
||||
// in that case. We still check this after analysis as all opque
|
||||
// types have been revealed at this point.
|
||||
if (src, dest).has_opaque_types() {
|
||||
return true;
|
||||
}
|
||||
|
||||
crate::util::is_subtype(self.tcx, self.param_env, src, dest)
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// #55810: Type check patterns first so we get types for all bindings.
|
||||
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
|
||||
for arm in arms {
|
||||
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), true);
|
||||
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
|
||||
}
|
||||
|
||||
// Now typecheck the blocks.
|
||||
|
@ -90,7 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||
// Check the pattern.
|
||||
let ty_span = try { inputs_hir?.get(idx)?.span };
|
||||
fcx.check_pat_top(¶m.pat, param_ty, ty_span, false);
|
||||
fcx.check_pat_top(¶m.pat, param_ty, ty_span, None);
|
||||
|
||||
// Check that argument is Sized.
|
||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||
|
@ -1330,11 +1330,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Does the expected pattern type originate from an expression and what is the span?
|
||||
let (origin_expr, ty_span) = match (decl.ty, decl.init) {
|
||||
(Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
|
||||
(Some(ty), _) => (None, Some(ty.span)), // Bias towards the explicit user type.
|
||||
(_, Some(init)) => {
|
||||
(true, Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
|
||||
(Some(init), Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
|
||||
} // No explicit type; so use the scrutinee.
|
||||
_ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
|
||||
_ => (None, None), // We have `let $pat;`, so the expected type is unconstrained.
|
||||
};
|
||||
|
||||
// Type check the pattern. Override if necessary to avoid knock-on errors.
|
||||
|
@ -46,7 +46,7 @@ struct TopInfo<'tcx> {
|
||||
/// Was the origin of the `span` from a scrutinee expression?
|
||||
///
|
||||
/// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter.
|
||||
origin_expr: bool,
|
||||
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
/// The span giving rise to the `expected` type, if one could be provided.
|
||||
///
|
||||
/// If `origin_expr` is `true`, then this is the span of the scrutinee as in:
|
||||
@ -74,7 +74,8 @@ struct TopInfo<'tcx> {
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
||||
let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
|
||||
let code =
|
||||
Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() };
|
||||
self.cause(cause_span, code)
|
||||
}
|
||||
|
||||
@ -85,7 +86,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
actual: Ty<'tcx>,
|
||||
ti: TopInfo<'tcx>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
|
||||
let mut diag =
|
||||
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
|
||||
if let Some(expr) = ti.origin_expr {
|
||||
self.suggest_fn_call(&mut diag, expr, expected, |output| {
|
||||
self.can_eq(self.param_env, output, actual).is_ok()
|
||||
});
|
||||
}
|
||||
Some(diag)
|
||||
}
|
||||
|
||||
fn demand_eqtype_pat(
|
||||
@ -127,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
span: Option<Span>,
|
||||
origin_expr: bool,
|
||||
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
) {
|
||||
let info = TopInfo { expected, origin_expr, span };
|
||||
self.check_pat(pat, expected, INITIAL_BM, info);
|
||||
@ -2146,7 +2154,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
||||
} else if self.autoderef(span, expected_ty)
|
||||
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||
&& let (Some(span), true) = (ti.span, ti.origin_expr)
|
||||
&& let Some(span) = ti.span
|
||||
&& let Some(_) = ti.origin_expr
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
let ty = self.resolve_vars_if_possible(ti.expected);
|
||||
|
@ -19,6 +19,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::is_range_literal;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
@ -1349,14 +1350,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// Issue #104961, we need to add parentheses properly for compond expressions
|
||||
// for example, `x.starts_with("hi".to_string() + "you")`
|
||||
// should be `x.starts_with(&("hi".to_string() + "you"))`
|
||||
let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; };
|
||||
let body = self.tcx.hir().body(body_id);
|
||||
let mut expr_finder = FindExprBySpan::new(span);
|
||||
expr_finder.visit_expr(body.value);
|
||||
let Some(expr) = expr_finder.result else { return false; };
|
||||
let needs_parens = match expr.kind {
|
||||
// parenthesize if needed (Issue #46756)
|
||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
||||
// parenthesize borrows of range literals (Issue #54505)
|
||||
_ if is_range_literal(expr) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider{} borrowing here",
|
||||
if is_mut { " mutably" } else { "" }
|
||||
),
|
||||
format!("&{}", if is_mut { "mut " } else { "" }),
|
||||
let span = if needs_parens { span } else { span.shrink_to_lo() };
|
||||
let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
|
||||
let sugg_msg = &format!(
|
||||
"consider{} borrowing here",
|
||||
if is_mut { " mutably" } else { "" }
|
||||
);
|
||||
|
||||
let suggestions = if !needs_parens {
|
||||
vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
|
||||
} else {
|
||||
vec![
|
||||
(span.shrink_to_lo(), format!("{}(", sugg_prefix)),
|
||||
(span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
};
|
||||
err.multipart_suggestion_verbose(
|
||||
sugg_msg,
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ pub unsafe trait GlobalAlloc {
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Shrink or grow a block of memory to the given `new_size`.
|
||||
/// Shrink or grow a block of memory to the given `new_size` in bytes.
|
||||
/// The block is described by the given `ptr` pointer and `layout`.
|
||||
///
|
||||
/// If this returns a non-null pointer, then ownership of the memory block
|
||||
@ -211,10 +211,11 @@ pub unsafe trait GlobalAlloc {
|
||||
/// Any access to the old `ptr` is Undefined Behavior, even if the
|
||||
/// allocation remained in-place. The newly returned pointer is the only valid pointer
|
||||
/// for accessing this memory now.
|
||||
///
|
||||
/// The new memory block is allocated with `layout`,
|
||||
/// but with the `size` updated to `new_size`. This new layout must be
|
||||
/// used when deallocating the new memory block with `dealloc`. The range
|
||||
/// `0..min(layout.size(), new_size)` of the new memory block is
|
||||
/// but with the `size` updated to `new_size` in bytes.
|
||||
/// This new layout must be used when deallocating the new memory block with `dealloc`.
|
||||
/// The range `0..min(layout.size(), new_size)` of the new memory block is
|
||||
/// guaranteed to have the same values as the original block.
|
||||
///
|
||||
/// If this method returns null, then ownership of the memory
|
||||
|
@ -141,12 +141,28 @@ mod imp {
|
||||
// list.
|
||||
let argv = ARGV.load(Ordering::Relaxed);
|
||||
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
|
||||
(0..argc)
|
||||
.map(|i| {
|
||||
let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
|
||||
OsStringExt::from_vec(cstr.to_bytes().to_vec())
|
||||
})
|
||||
.collect()
|
||||
let mut args = Vec::with_capacity(argc as usize);
|
||||
for i in 0..argc {
|
||||
let ptr = *argv.offset(i) as *const libc::c_char;
|
||||
|
||||
// Some C commandline parsers (e.g. GLib and Qt) are replacing already
|
||||
// handled arguments in `argv` with `NULL` and move them to the end. That
|
||||
// means that `argc` might be bigger than the actual number of non-`NULL`
|
||||
// pointers in `argv` at this point.
|
||||
//
|
||||
// To handle this we simply stop iterating at the first `NULL` argument.
|
||||
//
|
||||
// `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
|
||||
// after the first `NULL` can safely be ignored.
|
||||
if ptr.is_null() {
|
||||
break;
|
||||
}
|
||||
|
||||
let cstr = CStr::from_ptr(ptr);
|
||||
args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1393,6 +1393,8 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
|
||||
let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
|
||||
let data_ptr = data.0.as_mut_ptr();
|
||||
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
|
||||
// Zero the header to ensure it's fully initialized, including reserved parameters.
|
||||
*db = mem::zeroed();
|
||||
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
|
||||
let mut i = 0;
|
||||
// FIXME: this conversion is very hacky
|
||||
|
@ -18,7 +18,7 @@ use super::search_index::build_index;
|
||||
use super::write_shared::write_shared;
|
||||
use super::{
|
||||
collect_spans_and_sources, print_sidebar, scrape_examples_help, sidebar_module_like, AllTypes,
|
||||
LinkFromSrc, NameDoc, StylePath,
|
||||
LinkFromSrc, StylePath,
|
||||
};
|
||||
|
||||
use crate::clean::{self, types::ExternalLocation, ExternalCrate};
|
||||
@ -256,7 +256,7 @@ impl<'tcx> Context<'tcx> {
|
||||
}
|
||||
|
||||
/// Construct a map of items shown in the sidebar to a plain-text summary of their docs.
|
||||
fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
|
||||
fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<String>> {
|
||||
// BTreeMap instead of HashMap to get a sorted output
|
||||
let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new();
|
||||
let mut inserted: FxHashMap<ItemType, FxHashSet<Symbol>> = FxHashMap::default();
|
||||
@ -274,10 +274,7 @@ impl<'tcx> Context<'tcx> {
|
||||
if inserted.entry(short).or_default().insert(myname) {
|
||||
let short = short.to_string();
|
||||
let myname = myname.to_string();
|
||||
map.entry(short).or_default().push((
|
||||
myname,
|
||||
Some(item.doc_value().map_or_else(String::new, |s| plain_text_summary(&s))),
|
||||
));
|
||||
map.entry(short).or_default().push(myname);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,9 +83,6 @@ use crate::scrape_examples::{CallData, CallLocation};
|
||||
use crate::try_none;
|
||||
use crate::DOC_RUST_LANG_ORG_CHANNEL;
|
||||
|
||||
/// A pair of name and its optional document.
|
||||
pub(crate) type NameDoc = (String, Option<String>);
|
||||
|
||||
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
|
||||
|
@ -455,10 +455,7 @@ function loadCss(cssUrl) {
|
||||
const ul = document.createElement("ul");
|
||||
ul.className = "block " + shortty;
|
||||
|
||||
for (const item of filtered) {
|
||||
const name = item[0];
|
||||
const desc = item[1]; // can be null
|
||||
|
||||
for (const name of filtered) {
|
||||
let path;
|
||||
if (shortty === "mod") {
|
||||
path = name + "/index.html";
|
||||
@ -468,7 +465,6 @@ function loadCss(cssUrl) {
|
||||
const current_page = document.location.href.split("/").pop();
|
||||
const link = document.createElement("a");
|
||||
link.href = path;
|
||||
link.title = desc;
|
||||
if (path === current_page) {
|
||||
link.className = "current";
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
#![crate_type = "lib"]
|
||||
#![crate_name = "summaries"]
|
||||
|
||||
//! This *summary* has a [link] and `code`.
|
||||
//!
|
||||
//! This is the second paragraph.
|
||||
//!
|
||||
//! [link]: https://example.com
|
||||
|
||||
// @hasraw search-index.js 'This <em>summary</em> has a link and <code>code</code>.'
|
||||
// @!hasraw - 'second paragraph'
|
||||
|
||||
/// This `code` will be rendered in a code tag.
|
||||
///
|
||||
/// This text should not be rendered.
|
||||
pub struct Sidebar;
|
||||
|
||||
// @hasraw search-index.js 'This <code>code</code> will be rendered in a code tag.'
|
||||
// @hasraw summaries/sidebar-items.js 'This `code` will be rendered in a code tag.'
|
||||
// @!hasraw - 'text should not be rendered'
|
||||
|
||||
/// ```text
|
||||
/// this block should not be rendered
|
||||
/// ```
|
||||
pub struct Sidebar2;
|
||||
|
||||
// @!hasraw summaries/sidebar-items.js 'block should not be rendered'
|
19
tests/ui/const-generics/wrong-normalization.rs
Normal file
19
tests/ui/const-generics/wrong-normalization.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// This test ensures that if implementation on projections is supported,
|
||||
// it doesn't end in very weird cycle error.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub trait Identity {
|
||||
type Identity: ?Sized;
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Identity for T {
|
||||
type Identity = Self;
|
||||
}
|
||||
|
||||
pub struct I8<const F: i8>;
|
||||
|
||||
impl <I8<{i8::MIN}> as Identity>::Identity {
|
||||
//~^ ERROR no nominal type found for inherent implementation
|
||||
pub fn foo(&self) {}
|
||||
}
|
11
tests/ui/const-generics/wrong-normalization.stderr
Normal file
11
tests/ui/const-generics/wrong-normalization.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0118]: no nominal type found for inherent implementation
|
||||
--> $DIR/wrong-normalization.rs:16:6
|
||||
|
|
||||
LL | impl <I8<{i8::MIN}> as Identity>::Identity {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
|
||||
|
|
||||
= note: either implement a trait on it or create a newtype to wrap it instead
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0118`.
|
@ -1,4 +1,7 @@
|
||||
// check-pass
|
||||
// compile-flags: -Zvalidate-mir
|
||||
|
||||
// Using -Zvalidate-mir as a regression test for #107346.
|
||||
|
||||
trait Duh {}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
|
||||
--> $DIR/nested-return-type2.rs:25:24
|
||||
--> $DIR/nested-return-type2.rs:28:24
|
||||
|
|
||||
LL | type Assoc: Duh;
|
||||
| --- this associated type bound is unsatisfied for `impl Send`
|
||||
|
16
tests/ui/suggestions/issue-104961.fixed
Normal file
16
tests/ui/suggestions/issue-104961.fixed
Normal file
@ -0,0 +1,16 @@
|
||||
// run-rustfix
|
||||
|
||||
fn foo(x: &str) -> bool {
|
||||
x.starts_with(&("hi".to_string() + " you"))
|
||||
//~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
|
||||
}
|
||||
|
||||
fn foo2(x: &str) -> bool {
|
||||
x.starts_with(&"hi".to_string())
|
||||
//~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo("hi you");
|
||||
foo2("hi");
|
||||
}
|
16
tests/ui/suggestions/issue-104961.rs
Normal file
16
tests/ui/suggestions/issue-104961.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// run-rustfix
|
||||
|
||||
fn foo(x: &str) -> bool {
|
||||
x.starts_with("hi".to_string() + " you")
|
||||
//~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
|
||||
}
|
||||
|
||||
fn foo2(x: &str) -> bool {
|
||||
x.starts_with("hi".to_string())
|
||||
//~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo("hi you");
|
||||
foo2("hi");
|
||||
}
|
37
tests/ui/suggestions/issue-104961.stderr
Normal file
37
tests/ui/suggestions/issue-104961.stderr
Normal file
@ -0,0 +1,37 @@
|
||||
error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
|
||||
--> $DIR/issue-104961.rs:4:19
|
||||
|
|
||||
LL | x.starts_with("hi".to_string() + " you")
|
||||
| ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: the trait bound `String: Pattern<'_>` is not satisfied
|
||||
= note: required for `String` to implement `Pattern<'_>`
|
||||
note: required by a bound in `core::str::<impl str>::starts_with`
|
||||
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
||||
help: consider borrowing here
|
||||
|
|
||||
LL | x.starts_with(&("hi".to_string() + " you"))
|
||||
| ++ +
|
||||
|
||||
error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
|
||||
--> $DIR/issue-104961.rs:9:19
|
||||
|
|
||||
LL | x.starts_with("hi".to_string())
|
||||
| ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: the trait bound `String: Pattern<'_>` is not satisfied
|
||||
= note: required for `String` to implement `Pattern<'_>`
|
||||
note: required by a bound in `core::str::<impl str>::starts_with`
|
||||
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
||||
help: consider borrowing here
|
||||
|
|
||||
LL | x.starts_with(&"hi".to_string())
|
||||
| +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
16
tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
Normal file
16
tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
Normal file
@ -0,0 +1,16 @@
|
||||
enum E {
|
||||
One(i32, i32),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let var = E::One;
|
||||
if let E::One(var1, var2) = var {
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use parentheses to construct this tuple variant
|
||||
println!("{var1} {var2}");
|
||||
}
|
||||
|
||||
let Some(x) = Some;
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use parentheses to construct this tuple variant
|
||||
}
|
33
tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
Normal file
33
tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
Normal file
@ -0,0 +1,33 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-call-on-pat-mismatch.rs:7:12
|
||||
|
|
||||
LL | if let E::One(var1, var2) = var {
|
||||
| ^^^^^^^^^^^^^^^^^^ --- this expression has type `fn(i32, i32) -> E {E::One}`
|
||||
| |
|
||||
| expected enum constructor, found `E`
|
||||
|
|
||||
= note: expected enum constructor `fn(i32, i32) -> E {E::One}`
|
||||
found enum `E`
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | if let E::One(var1, var2) = var(/* i32 */, /* i32 */) {
|
||||
| ++++++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-call-on-pat-mismatch.rs:13:9
|
||||
|
|
||||
LL | let Some(x) = Some;
|
||||
| ^^^^^^^ ---- this expression has type `fn(_) -> Option<_> {Option::<_>::Some}`
|
||||
| |
|
||||
| expected enum constructor, found `Option<_>`
|
||||
|
|
||||
= note: expected enum constructor `fn(_) -> Option<_> {Option::<_>::Some}`
|
||||
found enum `Option<_>`
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | let Some(x) = Some(/* value */);
|
||||
| +++++++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,25 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
trait Foo {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Bar {}
|
||||
|
||||
impl<T> Foo for T {
|
||||
type Assoc = i32;
|
||||
}
|
||||
|
||||
impl<T> Bar for T where T: Foo<Assoc = i32> {}
|
||||
|
||||
fn require_bar<T: Bar>() {}
|
||||
|
||||
fn foo<T: Foo>() {
|
||||
// Unlike the classic solver, `<T as Foo>::Assoc = _` will still project
|
||||
// down to `i32` even though there's a param-env candidate here, since we
|
||||
// don't assemble any param-env projection candidates for `T: Foo` alone.
|
||||
require_bar::<T>();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,30 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// When we're solving `<T as Foo>::Assoc = i32`, we actually first solve
|
||||
// `<T as Foo>::Assoc = _#1t`, then unify `_#1t` with `i32`. That goal
|
||||
// with the inference variable is ambiguous when there are >1 param-env
|
||||
// candidates.
|
||||
|
||||
// We don't unify the RHS of a projection goal eagerly when solving, both
|
||||
// for caching reasons and partly to make sure that we don't make the new
|
||||
// trait solver smarter than it should be.
|
||||
|
||||
// This is (as far as I can tell) a forwards-compatible decision, but if you
|
||||
// make this test go from fail to pass, be sure you understand the implications!
|
||||
|
||||
trait Foo {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Bar {}
|
||||
|
||||
impl<T> Bar for T where T: Foo<Assoc = i32> {}
|
||||
|
||||
fn needs_bar<T: Bar>() {}
|
||||
|
||||
fn foo<T: Foo<Assoc = i32> + Foo<Assoc = u32>>() {
|
||||
needs_bar::<T>();
|
||||
//~^ ERROR type annotations needed: cannot satisfy `T: Bar`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,16 @@
|
||||
error[E0283]: type annotations needed: cannot satisfy `T: Bar`
|
||||
--> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:5
|
||||
|
|
||||
LL | needs_bar::<T>();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: cannot satisfy `T: Bar`
|
||||
note: required by a bound in `needs_bar`
|
||||
--> $DIR/two-projection-param-candidates-are-ambiguous.rs:23:17
|
||||
|
|
||||
LL | fn needs_bar<T: Bar>() {}
|
||||
| ^^^ required by this bound in `needs_bar`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
Loading…
Reference in New Issue
Block a user