mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
Auto merge of #92609 - matthiaskrgr:rollup-ldp47ot, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #92058 (Make Run button visible on hover) - #92288 (Fix a pair of mistyped test cases in `std::net::ip`) - #92349 (Fix rustdoc::private_doc_tests lint for public re-exported items) - #92360 (Some cleanups around check_argument_types) - #92389 (Regression test for borrowck ICE #92015) - #92404 (Fix font size for [src] links in headers) - #92443 (Rustdoc: resolve associated traits for non-generic primitive types) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
cfa4ac66c1
@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
call_expr.span,
|
call_expr.span,
|
||||||
call_expr,
|
call_expr,
|
||||||
fn_sig.inputs(),
|
fn_sig.inputs(),
|
||||||
&expected_arg_tys,
|
expected_arg_tys,
|
||||||
arg_exprs,
|
arg_exprs,
|
||||||
fn_sig.c_variadic,
|
fn_sig.c_variadic,
|
||||||
TupleArgumentsFlag::DontTupleArguments,
|
TupleArgumentsFlag::DontTupleArguments,
|
||||||
@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
call_expr.span,
|
call_expr.span,
|
||||||
call_expr,
|
call_expr,
|
||||||
fn_sig.inputs(),
|
fn_sig.inputs(),
|
||||||
&expected_arg_tys,
|
expected_arg_tys,
|
||||||
arg_exprs,
|
arg_exprs,
|
||||||
fn_sig.c_variadic,
|
fn_sig.c_variadic,
|
||||||
TupleArgumentsFlag::TupleArguments,
|
TupleArgumentsFlag::TupleArguments,
|
||||||
|
@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
sp,
|
sp,
|
||||||
expr,
|
expr,
|
||||||
&err_inputs,
|
&err_inputs,
|
||||||
&[],
|
vec![],
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
false,
|
false,
|
||||||
tuple_arguments,
|
tuple_arguments,
|
||||||
@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let method = method.unwrap();
|
let method = method.unwrap();
|
||||||
// HACK(eddyb) ignore self in the definition (see above).
|
// HACK(eddyb) ignore self in the definition (see above).
|
||||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
let expected_input_tys = self.expected_inputs_for_expected_output(
|
||||||
sp,
|
sp,
|
||||||
expected,
|
expected,
|
||||||
method.sig.output(),
|
method.sig.output(),
|
||||||
@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
sp,
|
sp,
|
||||||
expr,
|
expr,
|
||||||
&method.sig.inputs()[1..],
|
&method.sig.inputs()[1..],
|
||||||
&expected_arg_tys[..],
|
expected_input_tys,
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
method.sig.c_variadic,
|
method.sig.c_variadic,
|
||||||
tuple_arguments,
|
tuple_arguments,
|
||||||
@ -96,34 +96,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
/// method calls and overloaded operators.
|
/// method calls and overloaded operators.
|
||||||
pub(in super::super) fn check_argument_types(
|
pub(in super::super) fn check_argument_types(
|
||||||
&self,
|
&self,
|
||||||
sp: Span,
|
// Span enclosing the call site
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
call_span: Span,
|
||||||
fn_inputs: &[Ty<'tcx>],
|
// Expression of the call site
|
||||||
expected_arg_tys: &[Ty<'tcx>],
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
// Types (as defined in the *signature* of the target function)
|
||||||
|
formal_input_tys: &[Ty<'tcx>],
|
||||||
|
// More specific expected types, after unifying with caller output types
|
||||||
|
expected_input_tys: Vec<Ty<'tcx>>,
|
||||||
|
// The expressions for each provided argument
|
||||||
|
provided_args: &'tcx [hir::Expr<'tcx>],
|
||||||
|
// Whether the function is variadic, for example when imported from C
|
||||||
c_variadic: bool,
|
c_variadic: bool,
|
||||||
|
// Whether the arguments have been bundled in a tuple (ex: closures)
|
||||||
tuple_arguments: TupleArgumentsFlag,
|
tuple_arguments: TupleArgumentsFlag,
|
||||||
def_id: Option<DefId>,
|
// The DefId for the function being called, for better error messages
|
||||||
|
fn_def_id: Option<DefId>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
// Grab the argument types, supplying fresh type variables
|
// Grab the argument types, supplying fresh type variables
|
||||||
// if the wrong number of arguments were supplied
|
// if the wrong number of arguments were supplied
|
||||||
let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
|
let supplied_arg_count =
|
||||||
|
if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
|
||||||
|
|
||||||
// All the input types from the fn signature must outlive the call
|
// All the input types from the fn signature must outlive the call
|
||||||
// so as to validate implied bounds.
|
// so as to validate implied bounds.
|
||||||
for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) {
|
for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
|
||||||
self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
|
self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected_arg_count = fn_inputs.len();
|
let expected_arg_count = formal_input_tys.len();
|
||||||
|
|
||||||
let param_count_error = |expected_count: usize,
|
let param_count_error = |expected_count: usize,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
error_code: &str,
|
error_code: &str,
|
||||||
c_variadic: bool,
|
c_variadic: bool,
|
||||||
sugg_unit: bool| {
|
sugg_unit: bool| {
|
||||||
let (span, start_span, args, ctor_of) = match &expr.kind {
|
let (span, start_span, args, ctor_of) = match &call_expr.kind {
|
||||||
hir::ExprKind::Call(
|
hir::ExprKind::Call(
|
||||||
hir::Expr {
|
hir::Expr {
|
||||||
span,
|
span,
|
||||||
@ -156,14 +165,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&args[1..], // Skip the receiver.
|
&args[1..], // Skip the receiver.
|
||||||
None, // methods are never ctors
|
None, // methods are never ctors
|
||||||
),
|
),
|
||||||
k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
|
k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
|
||||||
};
|
};
|
||||||
let arg_spans = if args.is_empty() {
|
let arg_spans = if provided_args.is_empty() {
|
||||||
// foo()
|
// foo()
|
||||||
// ^^^-- supplied 0 arguments
|
// ^^^-- supplied 0 arguments
|
||||||
// |
|
// |
|
||||||
// expected 2 arguments
|
// expected 2 arguments
|
||||||
vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
|
vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
|
||||||
} else {
|
} else {
|
||||||
// foo(1, 2, 3)
|
// foo(1, 2, 3)
|
||||||
// ^^^ - - - supplied 3 arguments
|
// ^^^ - - - supplied 3 arguments
|
||||||
@ -196,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(def_id) = def_id {
|
if let Some(def_id) = fn_def_id {
|
||||||
if let Some(def_span) = tcx.def_ident_span(def_id) {
|
if let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||||
let mut spans: MultiSpan = def_span.into();
|
let mut spans: MultiSpan = def_span.into();
|
||||||
|
|
||||||
@ -218,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sugg_unit {
|
if sugg_unit {
|
||||||
let sugg_span = tcx.sess.source_map().end_point(expr.span);
|
let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
|
||||||
// remove closing `)` from the span
|
// remove closing `)` from the span
|
||||||
let sugg_span = sugg_span.shrink_to_lo();
|
let sugg_span = sugg_span.shrink_to_lo();
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
@ -240,110 +249,148 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err.emit();
|
err.emit();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut expected_arg_tys = expected_arg_tys.to_vec();
|
let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
|
||||||
|
let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
|
||||||
let formal_tys = if tuple_arguments == TupleArguments {
|
|
||||||
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
|
|
||||||
match tuple_type.kind() {
|
match tuple_type.kind() {
|
||||||
ty::Tuple(arg_types) if arg_types.len() != args.len() => {
|
ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
|
||||||
param_count_error(arg_types.len(), args.len(), "E0057", false, false);
|
param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
|
||||||
expected_arg_tys = vec![];
|
(self.err_args(provided_args.len()), vec![])
|
||||||
self.err_args(args.len())
|
|
||||||
}
|
}
|
||||||
ty::Tuple(arg_types) => {
|
ty::Tuple(arg_types) => {
|
||||||
expected_arg_tys = match expected_arg_tys.get(0) {
|
let expected_input_tys = match expected_input_tys.get(0) {
|
||||||
Some(&ty) => match ty.kind() {
|
Some(&ty) => match ty.kind() {
|
||||||
ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
|
ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
},
|
},
|
||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
arg_types.iter().map(|k| k.expect_ty()).collect()
|
(arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
sp,
|
call_span,
|
||||||
E0059,
|
E0059,
|
||||||
"cannot use call notation; the first type parameter \
|
"cannot use call notation; the first type parameter \
|
||||||
for the function trait is neither a tuple nor unit"
|
for the function trait is neither a tuple nor unit"
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
expected_arg_tys = vec![];
|
(self.err_args(provided_args.len()), vec![])
|
||||||
self.err_args(args.len())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if expected_arg_count == supplied_arg_count {
|
} else if expected_arg_count == supplied_arg_count {
|
||||||
fn_inputs.to_vec()
|
(formal_input_tys.to_vec(), expected_input_tys)
|
||||||
} else if c_variadic {
|
} else if c_variadic {
|
||||||
if supplied_arg_count >= expected_arg_count {
|
if supplied_arg_count >= expected_arg_count {
|
||||||
fn_inputs.to_vec()
|
(formal_input_tys.to_vec(), expected_input_tys)
|
||||||
} else {
|
} else {
|
||||||
param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
|
param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
|
||||||
expected_arg_tys = vec![];
|
(self.err_args(supplied_arg_count), vec![])
|
||||||
self.err_args(supplied_arg_count)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// is the missing argument of type `()`?
|
// is the missing argument of type `()`?
|
||||||
let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
|
let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 {
|
||||||
self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
|
self.resolve_vars_if_possible(expected_input_tys[0]).is_unit()
|
||||||
} else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
|
} else if formal_input_tys.len() == 1 && supplied_arg_count == 0 {
|
||||||
self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
|
self.resolve_vars_if_possible(formal_input_tys[0]).is_unit()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
|
param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
|
||||||
|
|
||||||
expected_arg_tys = vec![];
|
(self.err_args(supplied_arg_count), vec![])
|
||||||
self.err_args(supplied_arg_count)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"check_argument_types: formal_tys={:?}",
|
"check_argument_types: formal_input_tys={:?}",
|
||||||
formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
|
formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
// If there is no expectation, expect formal_tys.
|
// If there is no expectation, expect formal_input_tys.
|
||||||
let expected_arg_tys =
|
let expected_input_tys = if !expected_input_tys.is_empty() {
|
||||||
if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
|
expected_input_tys
|
||||||
|
} else {
|
||||||
|
formal_input_tys.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(expected_input_tys.len(), formal_input_tys.len());
|
||||||
|
|
||||||
|
// Keep track of the fully coerced argument types
|
||||||
let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
|
let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
|
||||||
|
|
||||||
|
// We introduce a helper function to demand that a given argument satisfy a given input
|
||||||
|
// This is more complicated than just checking type equality, as arguments could be coerced
|
||||||
|
// This version writes those types back so further type checking uses the narrowed types
|
||||||
|
let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
|
||||||
|
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
|
||||||
|
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
|
||||||
|
let provided_arg = &provided_args[idx];
|
||||||
|
|
||||||
|
debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
|
||||||
|
|
||||||
|
// The special-cased logic below has three functions:
|
||||||
|
// 1. Provide as good of an expected type as possible.
|
||||||
|
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
|
||||||
|
|
||||||
|
let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
|
||||||
|
|
||||||
|
// 2. Coerce to the most detailed type that could be coerced
|
||||||
|
// to, which is `expected_ty` if `rvalue_hint` returns an
|
||||||
|
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
|
||||||
|
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
|
||||||
|
|
||||||
|
// Keep track of these for below
|
||||||
|
final_arg_types.push((idx, checked_ty, coerced_ty));
|
||||||
|
|
||||||
|
// Cause selection errors caused by resolving a single argument to point at the
|
||||||
|
// argument and not the call. This is otherwise redundant with the `demand_coerce`
|
||||||
|
// call immediately after, but it lets us customize the span pointed to in the
|
||||||
|
// fulfillment error to be more accurate.
|
||||||
|
let _ =
|
||||||
|
self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
|
||||||
|
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
|
||||||
|
self.point_at_arg_instead_of_call_if_possible(
|
||||||
|
errors,
|
||||||
|
&final_arg_types,
|
||||||
|
call_expr,
|
||||||
|
call_span,
|
||||||
|
provided_args,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// We're processing function arguments so we definitely want to use
|
||||||
|
// two-phase borrows.
|
||||||
|
self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
|
||||||
|
|
||||||
|
// 3. Relate the expected type and the formal one,
|
||||||
|
// if the expected type was used for the coercion.
|
||||||
|
self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
|
||||||
|
};
|
||||||
|
|
||||||
// Check the arguments.
|
// Check the arguments.
|
||||||
// We do this in a pretty awful way: first we type-check any arguments
|
// We do this in a pretty awful way: first we type-check any arguments
|
||||||
// that are not closures, then we type-check the closures. This is so
|
// that are not closures, then we type-check the closures. This is so
|
||||||
// that we have more information about the types of arguments when we
|
// that we have more information about the types of arguments when we
|
||||||
// type-check the functions. This isn't really the right way to do this.
|
// type-check the functions. This isn't really the right way to do this.
|
||||||
for check_closures in [false, true] {
|
for check_closures in [false, true] {
|
||||||
debug!("check_closures={}", check_closures);
|
|
||||||
|
|
||||||
// More awful hacks: before we check argument types, try to do
|
// More awful hacks: before we check argument types, try to do
|
||||||
// an "opportunistic" trait resolution of any trait bounds on
|
// an "opportunistic" trait resolution of any trait bounds on
|
||||||
// the call. This helps coercions.
|
// the call. This helps coercions.
|
||||||
if check_closures {
|
if check_closures {
|
||||||
self.select_obligations_where_possible(false, |errors| {
|
self.select_obligations_where_possible(false, |errors| {
|
||||||
self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
|
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
|
||||||
self.point_at_arg_instead_of_call_if_possible(
|
self.point_at_arg_instead_of_call_if_possible(
|
||||||
errors,
|
errors,
|
||||||
&final_arg_types,
|
&final_arg_types,
|
||||||
expr,
|
call_expr,
|
||||||
sp,
|
call_span,
|
||||||
&args,
|
&provided_args,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// For C-variadic functions, we don't have a declared type for all of
|
let minimum_input_count = formal_input_tys.len();
|
||||||
// the arguments hence we only do our usual type checking with
|
for (idx, arg) in provided_args.iter().enumerate() {
|
||||||
// the arguments who's types we do know.
|
|
||||||
let t = if c_variadic {
|
|
||||||
expected_arg_count
|
|
||||||
} else if tuple_arguments == TupleArguments {
|
|
||||||
args.len()
|
|
||||||
} else {
|
|
||||||
supplied_arg_count
|
|
||||||
};
|
|
||||||
for (i, arg) in args.iter().take(t).enumerate() {
|
|
||||||
// Warn only for the first loop (the "no closures" one).
|
// Warn only for the first loop (the "no closures" one).
|
||||||
// Closure arguments themselves can't be diverging, but
|
// Closure arguments themselves can't be diverging, but
|
||||||
// a previous argument can, e.g., `foo(panic!(), || {})`.
|
// a previous argument can, e.g., `foo(panic!(), || {})`.
|
||||||
@ -351,53 +398,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
|
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_closure = matches!(arg.kind, ExprKind::Closure(..));
|
// For C-variadic functions, we don't have a declared type for all of
|
||||||
|
// the arguments hence we only do our usual type checking with
|
||||||
|
// the arguments who's types we do know. However, we *can* check
|
||||||
|
// for unreachable expressions (see above).
|
||||||
|
// FIXME: unreachable warning current isn't emitted
|
||||||
|
if idx >= minimum_input_count {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_closure = matches!(arg.kind, ExprKind::Closure(..));
|
||||||
if is_closure != check_closures {
|
if is_closure != check_closures {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let formal_ty = formal_tys[i];
|
demand_compatible(idx, &mut final_arg_types);
|
||||||
debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
|
|
||||||
|
|
||||||
// The special-cased logic below has three functions:
|
|
||||||
// 1. Provide as good of an expected type as possible.
|
|
||||||
let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
|
|
||||||
|
|
||||||
let checked_ty = self.check_expr_with_expectation(&arg, expected);
|
|
||||||
|
|
||||||
// 2. Coerce to the most detailed type that could be coerced
|
|
||||||
// to, which is `expected_ty` if `rvalue_hint` returns an
|
|
||||||
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
|
|
||||||
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
|
|
||||||
|
|
||||||
final_arg_types.push((i, checked_ty, coerce_ty));
|
|
||||||
|
|
||||||
// Cause selection errors caused by resolving a single argument to point at the
|
|
||||||
// argument and not the call. This is otherwise redundant with the `demand_coerce`
|
|
||||||
// call immediately after, but it lets us customize the span pointed to in the
|
|
||||||
// fulfillment error to be more accurate.
|
|
||||||
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
|
|
||||||
coerce_ty,
|
|
||||||
|errors| {
|
|
||||||
self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
|
|
||||||
self.point_at_arg_instead_of_call_if_possible(
|
|
||||||
errors,
|
|
||||||
&final_arg_types,
|
|
||||||
expr,
|
|
||||||
sp,
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// We're processing function arguments so we definitely want to use
|
|
||||||
// two-phase borrows.
|
|
||||||
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
|
|
||||||
|
|
||||||
// 3. Relate the expected type and the formal one,
|
|
||||||
// if the expected type was used for the coercion.
|
|
||||||
self.demand_suptype(arg.span, formal_ty, coerce_ty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
|
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
for arg in args.iter().skip(expected_arg_count) {
|
for arg in provided_args.iter().skip(expected_arg_count) {
|
||||||
let arg_ty = self.check_expr(&arg);
|
let arg_ty = self.check_expr(&arg);
|
||||||
|
|
||||||
// There are a few types which get autopromoted when passed via varargs
|
// There are a few types which get autopromoted when passed via varargs
|
||||||
|
@ -77,10 +77,10 @@ fn test_from_str_ipv4_in_ipv6() {
|
|||||||
let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
|
let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
|
||||||
assert_eq!(None, none);
|
assert_eq!(None, none);
|
||||||
// not enough groups
|
// not enough groups
|
||||||
let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
|
let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
|
||||||
assert_eq!(None, none);
|
assert_eq!(None, none);
|
||||||
// too many groups
|
// too many groups
|
||||||
let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
|
let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
|
||||||
assert_eq!(None, none);
|
assert_eq!(None, none);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1080,8 +1080,11 @@ body.blur > :not(#help) {
|
|||||||
|
|
||||||
.impl-items .srclink, .impl .srclink, .methods .srclink {
|
.impl-items .srclink, .impl .srclink, .methods .srclink {
|
||||||
/* Override header settings otherwise it's too bold */
|
/* Override header settings otherwise it's too bold */
|
||||||
font-size: 1.0625rem;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.impl .srclink {
|
||||||
|
font-size: 1.0625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rightside {
|
.rightside {
|
||||||
@ -1117,6 +1120,7 @@ pre.rust .question-mark {
|
|||||||
|
|
||||||
a.test-arrow {
|
a.test-arrow {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
visibility: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 5px 10px 5px 10px;
|
padding: 5px 10px 5px 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -1125,10 +1129,12 @@ a.test-arrow {
|
|||||||
right: 5px;
|
right: 5px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
.example-wrap:hover .test-arrow {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
a.test-arrow:hover{
|
a.test-arrow:hover{
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-header:hover a:before {
|
.section-header:hover a:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -25px;
|
left: -25px;
|
||||||
|
@ -351,11 +351,8 @@ a.test-arrow:hover {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
:target, :target > * {
|
|
||||||
background: rgba(255, 236, 164, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
:target {
|
:target {
|
||||||
|
background: rgba(255, 236, 164, 0.06);
|
||||||
border-right: 3px solid rgba(255, 180, 76, 0.85);
|
border-right: 3px solid rgba(255, 180, 76, 0.85);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,11 +295,8 @@ a.test-arrow:hover{
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
:target, :target > * {
|
|
||||||
background-color: #494a3d;
|
|
||||||
}
|
|
||||||
|
|
||||||
:target {
|
:target {
|
||||||
|
background-color: #494a3d;
|
||||||
border-right: 3px solid #bb7410;
|
border-right: 3px solid #bb7410;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,11 +284,8 @@ a.test-arrow:hover{
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
:target, :target > * {
|
|
||||||
background: #FDFFD3;
|
|
||||||
}
|
|
||||||
|
|
||||||
:target {
|
:target {
|
||||||
|
background: #FDFFD3;
|
||||||
border-right: 3px solid #AD7C37;
|
border-right: 3px solid #AD7C37;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if tests.found_tests > 0
|
} else if tests.found_tests > 0
|
||||||
&& !cx.cache.access_levels.is_public(item.def_id.expect_def_id())
|
&& !cx.cache.access_levels.is_exported(item.def_id.expect_def_id())
|
||||||
{
|
{
|
||||||
cx.tcx.struct_span_lint_hir(
|
cx.tcx.struct_span_lint_hir(
|
||||||
crate::lint::PRIVATE_DOC_TESTS,
|
crate::lint::PRIVATE_DOC_TESTS,
|
||||||
|
@ -13,7 +13,7 @@ use rustc_hir::def::{
|
|||||||
PerNS,
|
PerNS,
|
||||||
};
|
};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId};
|
use rustc_hir::def_id::{CrateNum, DefId};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::{Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug, ty};
|
use rustc_middle::{bug, span_bug, ty};
|
||||||
use rustc_resolve::ParentScope;
|
use rustc_resolve::ParentScope;
|
||||||
use rustc_session::lint::Lint;
|
use rustc_session::lint::Lint;
|
||||||
@ -618,6 +618,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a PrimitiveType to a Ty, where possible.
|
||||||
|
///
|
||||||
|
/// This is used for resolving trait impls for primitives
|
||||||
|
fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
|
||||||
|
use PrimitiveType::*;
|
||||||
|
let tcx = self.cx.tcx;
|
||||||
|
|
||||||
|
// FIXME: Only simple types are supported here, see if we can support
|
||||||
|
// other types such as Tuple, Array, Slice, etc.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
|
||||||
|
Some(tcx.mk_ty(match prim {
|
||||||
|
Bool => ty::Bool,
|
||||||
|
Str => ty::Str,
|
||||||
|
Char => ty::Char,
|
||||||
|
Never => ty::Never,
|
||||||
|
I8 => ty::Int(ty::IntTy::I8),
|
||||||
|
I16 => ty::Int(ty::IntTy::I16),
|
||||||
|
I32 => ty::Int(ty::IntTy::I32),
|
||||||
|
I64 => ty::Int(ty::IntTy::I64),
|
||||||
|
I128 => ty::Int(ty::IntTy::I128),
|
||||||
|
Isize => ty::Int(ty::IntTy::Isize),
|
||||||
|
F32 => ty::Float(ty::FloatTy::F32),
|
||||||
|
F64 => ty::Float(ty::FloatTy::F64),
|
||||||
|
U8 => ty::Uint(ty::UintTy::U8),
|
||||||
|
U16 => ty::Uint(ty::UintTy::U16),
|
||||||
|
U32 => ty::Uint(ty::UintTy::U32),
|
||||||
|
U64 => ty::Uint(ty::UintTy::U64),
|
||||||
|
U128 => ty::Uint(ty::UintTy::U128),
|
||||||
|
Usize => ty::Uint(ty::UintTy::Usize),
|
||||||
|
_ => return None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns:
|
/// Returns:
|
||||||
/// - None if no associated item was found
|
/// - None if no associated item was found
|
||||||
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
|
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
|
||||||
@ -632,7 +665,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
let tcx = self.cx.tcx;
|
let tcx = self.cx.tcx;
|
||||||
|
|
||||||
match root_res {
|
match root_res {
|
||||||
Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
|
Res::Primitive(prim) => {
|
||||||
|
self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| {
|
||||||
|
let assoc_item = self
|
||||||
|
.primitive_type_to_ty(prim)
|
||||||
|
.map(|ty| {
|
||||||
|
resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
assoc_item.map(|item| {
|
||||||
|
let kind = item.kind;
|
||||||
|
let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
|
||||||
|
// HACK(jynelson): `clean` expects the type, not the associated item
|
||||||
|
// but the disambiguator logic expects the associated item.
|
||||||
|
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
||||||
|
(root_res, fragment, Some((kind.as_def_kind(), item.def_id)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
Res::Def(DefKind::TyAlias, did) => {
|
Res::Def(DefKind::TyAlias, did) => {
|
||||||
// Resolve the link on the type the alias points to.
|
// Resolve the link on the type the alias points to.
|
||||||
// FIXME: if the associated item is defined directly on the type alias,
|
// FIXME: if the associated item is defined directly on the type alias,
|
||||||
@ -666,8 +717,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
// To handle that properly resolve() would have to support
|
// To handle that properly resolve() would have to support
|
||||||
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
|
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let item =
|
let item = resolve_associated_trait_item(
|
||||||
resolve_associated_trait_item(did, module_id, item_name, ns, self.cx);
|
tcx.type_of(did),
|
||||||
|
module_id,
|
||||||
|
item_name,
|
||||||
|
ns,
|
||||||
|
self.cx,
|
||||||
|
);
|
||||||
debug!("got associated item {:?}", item);
|
debug!("got associated item {:?}", item);
|
||||||
item
|
item
|
||||||
});
|
});
|
||||||
@ -767,12 +823,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
|
/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
|
||||||
/// find `std::error::Error::source` and return
|
/// find `std::error::Error::source` and return
|
||||||
/// `<io::Error as error::Error>::source`.
|
/// `<io::Error as error::Error>::source`.
|
||||||
fn resolve_associated_trait_item(
|
fn resolve_associated_trait_item<'a>(
|
||||||
did: DefId,
|
ty: Ty<'a>,
|
||||||
module: DefId,
|
module: DefId,
|
||||||
item_name: Symbol,
|
item_name: Symbol,
|
||||||
ns: Namespace,
|
ns: Namespace,
|
||||||
cx: &mut DocContext<'_>,
|
cx: &mut DocContext<'a>,
|
||||||
) -> Option<ty::AssocItem> {
|
) -> Option<ty::AssocItem> {
|
||||||
// FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
|
// FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
|
||||||
// `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
|
// `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
|
||||||
@ -780,7 +836,7 @@ fn resolve_associated_trait_item(
|
|||||||
|
|
||||||
// Next consider explicit impls: `impl MyTrait for MyType`
|
// Next consider explicit impls: `impl MyTrait for MyType`
|
||||||
// Give precedence to inherent impls.
|
// Give precedence to inherent impls.
|
||||||
let traits = traits_implemented_by(cx, did, module);
|
let traits = traits_implemented_by(cx, ty, module);
|
||||||
debug!("considering traits {:?}", traits);
|
debug!("considering traits {:?}", traits);
|
||||||
let mut candidates = traits.iter().filter_map(|&trait_| {
|
let mut candidates = traits.iter().filter_map(|&trait_| {
|
||||||
cx.tcx.associated_items(trait_).find_by_name_and_namespace(
|
cx.tcx.associated_items(trait_).find_by_name_and_namespace(
|
||||||
@ -799,7 +855,11 @@ fn resolve_associated_trait_item(
|
|||||||
///
|
///
|
||||||
/// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
|
/// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
|
||||||
/// So it is not stable to serialize cross-crate.
|
/// So it is not stable to serialize cross-crate.
|
||||||
fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet<DefId> {
|
fn traits_implemented_by<'a>(
|
||||||
|
cx: &mut DocContext<'a>,
|
||||||
|
ty: Ty<'a>,
|
||||||
|
module: DefId,
|
||||||
|
) -> FxHashSet<DefId> {
|
||||||
let mut resolver = cx.resolver.borrow_mut();
|
let mut resolver = cx.resolver.borrow_mut();
|
||||||
let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
|
let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
|
||||||
resolver.access(|resolver| {
|
resolver.access(|resolver| {
|
||||||
@ -813,7 +873,6 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
|
|||||||
});
|
});
|
||||||
|
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
let ty = tcx.type_of(type_);
|
|
||||||
let iter = in_scope_traits.iter().flat_map(|&trait_| {
|
let iter = in_scope_traits.iter().flat_map(|&trait_| {
|
||||||
trace!("considering explicit impl for trait {:?}", trait_);
|
trace!("considering explicit impl for trait {:?}", trait_);
|
||||||
|
|
||||||
@ -826,19 +885,10 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
|
|||||||
"comparing type {} with kind {:?} against type {:?}",
|
"comparing type {} with kind {:?} against type {:?}",
|
||||||
impl_type,
|
impl_type,
|
||||||
impl_type.kind(),
|
impl_type.kind(),
|
||||||
type_
|
ty
|
||||||
);
|
);
|
||||||
// Fast path: if this is a primitive simple `==` will work
|
// Fast path: if this is a primitive simple `==` will work
|
||||||
let saw_impl = impl_type == ty
|
let saw_impl = impl_type == ty;
|
||||||
|| match impl_type.kind() {
|
|
||||||
// Check if these are the same def_id
|
|
||||||
ty::Adt(def, _) => {
|
|
||||||
debug!("adt def_id: {:?}", def.did);
|
|
||||||
def.did == type_
|
|
||||||
}
|
|
||||||
ty::Foreign(def_id) => *def_id == type_,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if saw_impl { Some(trait_) } else { None }
|
if saw_impl { Some(trait_) } else { None }
|
||||||
})
|
})
|
||||||
|
7
src/test/rustdoc-gui/run-on-hover.goml
Normal file
7
src/test/rustdoc-gui/run-on-hover.goml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Example code blocks sometimes have a "Run" button to run them on the
|
||||||
|
// Playground. That button is hidden until the user hovers over the code block.
|
||||||
|
// This test checks that it is hidden, and that it shows on hover.
|
||||||
|
goto: file://|DOC_PATH|/test_docs/fn.foo.html
|
||||||
|
assert-css: (".test-arrow", {"visibility": "hidden"})
|
||||||
|
move-cursor-to: ".example-wrap"
|
||||||
|
assert-css: (".test-arrow", {"visibility": "visible"})
|
12
src/test/rustdoc-gui/src-font-size.goml
Normal file
12
src/test/rustdoc-gui/src-font-size.goml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// This test ensures that the "[src]" have the same font size as their headers
|
||||||
|
// to avoid having some weird height difference in the background when the element
|
||||||
|
// is selected.
|
||||||
|
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
|
||||||
|
show-text: true
|
||||||
|
// Check the impl headers.
|
||||||
|
assert-css: (".impl.has-srclink .srclink", {"font-size": "17px"}, ALL)
|
||||||
|
// The ".6" part is because the font-size is actually "1.1em".
|
||||||
|
assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "17.6px"}, ALL)
|
||||||
|
// Check the impl items.
|
||||||
|
assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
|
||||||
|
assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
|
@ -1,5 +1,6 @@
|
|||||||
//! The point of this crate is to be able to have enough different "kinds" of
|
//! The point of this crate is to be able to have enough different "kinds" of
|
||||||
//! documentation generated so we can test each different features.
|
//! documentation generated so we can test each different features.
|
||||||
|
#![doc(html_playground_url="https://play.rust-lang.org/")]
|
||||||
|
|
||||||
#![crate_name = "test_docs"]
|
#![crate_name = "test_docs"]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
//! [unit::eq] //~ ERROR unresolved
|
//! [unit::eq] //~ ERROR unresolved
|
||||||
//! [tuple::eq] //~ ERROR unresolved
|
//! [tuple::eq] //~ ERROR unresolved
|
||||||
//! [fn::eq] //~ ERROR unresolved
|
//! [fn::eq] //~ ERROR unresolved
|
||||||
//! [never::eq] //~ ERROR unresolved
|
|
||||||
|
|
||||||
// FIXME(#78800): This breaks because it's a blanket impl
|
// FIXME(#78800): This breaks because it's a blanket impl
|
||||||
// (I think? Might break for other reasons too.)
|
// (I think? Might break for other reasons too.)
|
||||||
|
@ -53,17 +53,11 @@ error: unresolved link to `fn::eq`
|
|||||||
LL | //! [fn::eq]
|
LL | //! [fn::eq]
|
||||||
| ^^^^^^ the builtin type `fn` has no associated item named `eq`
|
| ^^^^^^ the builtin type `fn` has no associated item named `eq`
|
||||||
|
|
||||||
error: unresolved link to `never::eq`
|
|
||||||
--> $DIR/non-path-primitives.rs:31:6
|
|
||||||
|
|
|
||||||
LL | //! [never::eq]
|
|
||||||
| ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
|
|
||||||
|
|
||||||
error: unresolved link to `reference::deref`
|
error: unresolved link to `reference::deref`
|
||||||
--> $DIR/non-path-primitives.rs:35:6
|
--> $DIR/non-path-primitives.rs:34:6
|
||||||
|
|
|
|
||||||
LL | //! [reference::deref]
|
LL | //! [reference::deref]
|
||||||
| ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
|
| ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
11
src/test/rustdoc-ui/private-public-item-doc-test.rs
Normal file
11
src/test/rustdoc-ui/private-public-item-doc-test.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#![deny(rustdoc::private_doc_tests)]
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
/// private doc test
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert!(false);
|
||||||
|
/// ```
|
||||||
|
//~^^^^^ ERROR documentation test in private item
|
||||||
|
pub fn bar() {}
|
||||||
|
}
|
18
src/test/rustdoc-ui/private-public-item-doc-test.stderr
Normal file
18
src/test/rustdoc-ui/private-public-item-doc-test.stderr
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
error: documentation test in private item
|
||||||
|
--> $DIR/private-public-item-doc-test.rs:4:5
|
||||||
|
|
|
||||||
|
LL | / /// private doc test
|
||||||
|
LL | | ///
|
||||||
|
LL | | /// ```
|
||||||
|
LL | | /// assert!(false);
|
||||||
|
LL | | /// ```
|
||||||
|
| |___________^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/private-public-item-doc-test.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rustdoc::private_doc_tests)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
16
src/test/rustdoc-ui/public-reexported-item-doc-test.rs
Normal file
16
src/test/rustdoc-ui/public-reexported-item-doc-test.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![deny(rustdoc::private_doc_tests)]
|
||||||
|
|
||||||
|
pub fn foo() {}
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
/// re-exported doc test
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert!(true);
|
||||||
|
/// ```
|
||||||
|
pub fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use private::bar;
|
46
src/test/rustdoc/intra-doc/prim-associated-traits.rs
Normal file
46
src/test/rustdoc/intra-doc/prim-associated-traits.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#![feature(never_type)]
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
|
||||||
|
// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
|
||||||
|
/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
|
||||||
|
/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
|
||||||
|
/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
|
||||||
|
/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
|
||||||
|
/// [`str::eq()`] [`never::eq()`]
|
||||||
|
pub struct Number {
|
||||||
|
pub f_64: f64,
|
||||||
|
pub f_32: f32,
|
||||||
|
pub i_size: isize,
|
||||||
|
pub i_8: i8,
|
||||||
|
pub i_16: i16,
|
||||||
|
pub i_32: i32,
|
||||||
|
pub i_64: i64,
|
||||||
|
pub i_128: i128,
|
||||||
|
pub u_size: usize,
|
||||||
|
pub u_8: u8,
|
||||||
|
pub u_16: u16,
|
||||||
|
pub u_32: u32,
|
||||||
|
pub u_64: u64,
|
||||||
|
pub u_128: u128,
|
||||||
|
pub ch: char,
|
||||||
|
pub boolean: bool,
|
||||||
|
pub string: str,
|
||||||
|
pub n: !,
|
||||||
|
}
|
7
src/test/ui/borrowck/issue-92015.rs
Normal file
7
src/test/ui/borrowck/issue-92015.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Regression test for #92105.
|
||||||
|
// ICE when mutating immutable reference from last statement of a block.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Some(&0).unwrap();
|
||||||
|
*foo = 1; //~ ERROR cannot assign
|
||||||
|
}
|
11
src/test/ui/borrowck/issue-92015.stderr
Normal file
11
src/test/ui/borrowck/issue-92015.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
|
||||||
|
--> $DIR/issue-92015.rs:6:5
|
||||||
|
|
|
||||||
|
LL | let foo = Some(&0).unwrap();
|
||||||
|
| --- help: consider changing this to be a mutable reference: `&mut i32`
|
||||||
|
LL | *foo = 1;
|
||||||
|
| ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0594`.
|
14
src/test/ui/c-variadic/variadic-unreachable-arg-error.rs
Normal file
14
src/test/ui/c-variadic/variadic-unreachable-arg-error.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn foo(f: isize, x: u8, ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
// FIXME: Ideally we could give an unreachable warning
|
||||||
|
foo(1, loop {}, 1usize);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user