mirror of https://github.com/rust-lang/rust.git
Auto merge of #131797 - matthiaskrgr:rollup-lzpze2k, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #130989 (Don't check unsize goal in MIR validation when opaques remain) - #131657 (Rustfmt `for<'a> async` correctly) - #131691 (Delay ambiguous intra-doc link resolution after `Cache` has been populated) - #131730 (Refactor some `core::fmt` macros) - #131751 (Rename `can_coerce` to `may_coerce`, and then structurally resolve correctly in the probe) - #131753 (Unify `secondary_span` and `swap_secondary_and_primary` args in `note_type_err`) - #131776 (Emscripten: Xfail backtrace ui tests) - #131777 (Fix trivially_copy_pass_by_ref in stable_mir) - #131778 (Fix needless_lifetimes in stable_mir) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
798fb83f7d
|
@ -592,14 +592,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
&cause,
|
||||
hir.get_if_local(impl_m.def_id)
|
||||
.and_then(|node| node.fn_decl())
|
||||
.map(|decl| (decl.output.span(), Cow::from("return type in trait"))),
|
||||
.map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),
|
||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||
expected: trait_return_ty.into(),
|
||||
found: impl_return_ty.into(),
|
||||
})),
|
||||
terr,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
}
|
||||
|
@ -1018,14 +1017,13 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_err_span.map(|sp| (sp, Cow::from("type in trait"))),
|
||||
trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),
|
||||
Some(infer::ValuePairs::PolySigs(ExpectedFound {
|
||||
expected: ty::Binder::dummy(trait_sig),
|
||||
found: ty::Binder::dummy(impl_sig),
|
||||
})),
|
||||
terr,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
diag.emit()
|
||||
|
@ -1825,14 +1823,13 @@ fn compare_const_predicate_entailment<'tcx>(
|
|||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_c_span.map(|span| (span, Cow::from("type in trait"))),
|
||||
trait_c_span.map(|span| (span, Cow::from("type in trait"), false)),
|
||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||
expected: trait_ty.into(),
|
||||
found: impl_ty.into(),
|
||||
})),
|
||||
terr,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
};
|
||||
|
|
|
@ -652,7 +652,6 @@ pub fn check_function_signature<'tcx>(
|
|||
})),
|
||||
err,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
}
|
||||
|
|
|
@ -235,8 +235,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(ret_coercion) => {
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.infcx.shallow_resolve(ret_ty);
|
||||
self.can_coerce(arm_ty, ret_ty)
|
||||
&& prior_arm.is_none_or(|(_, ty, _)| self.can_coerce(ty, ret_ty))
|
||||
self.may_coerce(arm_ty, ret_ty)
|
||||
&& prior_arm.is_none_or(|(_, ty, _)| self.may_coerce(ty, ret_ty))
|
||||
// The match arms need to unify for the case of `impl Trait`.
|
||||
&& !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..))
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
let mut sugg_mutref = false;
|
||||
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
|
||||
if let ty::RawPtr(expr_ty, _) = *self.expr_ty.kind()
|
||||
&& fcx.can_coerce(
|
||||
&& fcx.may_coerce(
|
||||
Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, expr_ty, mutbl),
|
||||
self.cast_ty,
|
||||
)
|
||||
|
@ -418,14 +418,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
} else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
|
||||
&& expr_mutbl == Mutability::Not
|
||||
&& mutbl == Mutability::Mut
|
||||
&& fcx.can_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty)
|
||||
&& fcx.may_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty)
|
||||
{
|
||||
sugg_mutref = true;
|
||||
}
|
||||
|
||||
if !sugg_mutref
|
||||
&& sugg == None
|
||||
&& fcx.can_coerce(
|
||||
&& fcx.may_coerce(
|
||||
Ty::new_ref(fcx.tcx, reg, self.expr_ty, mutbl),
|
||||
self.cast_ty,
|
||||
)
|
||||
|
@ -433,7 +433,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
|
||||
}
|
||||
} else if let ty::RawPtr(_, mutbl) = *self.cast_ty.kind()
|
||||
&& fcx.can_coerce(
|
||||
&& fcx.may_coerce(
|
||||
Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, self.expr_ty, mutbl),
|
||||
self.cast_ty,
|
||||
)
|
||||
|
|
|
@ -1084,24 +1084,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Same as `coerce()`, but without side-effects.
|
||||
/// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects,
|
||||
/// and may return false positives if types are not yet fully constrained by inference.
|
||||
///
|
||||
/// Returns false if the coercion creates any obligations that result in
|
||||
/// errors.
|
||||
pub(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
||||
// FIXME(-Znext-solver): We need to structurally resolve both types here.
|
||||
let source = self.resolve_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
|
||||
|
||||
/// Returns false if the coercion is not possible, or if the coercion creates any
|
||||
/// sub-obligations that result in errors.
|
||||
///
|
||||
/// This should only be used for diagnostics.
|
||||
pub(crate) fn may_coerce(&self, expr_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> bool {
|
||||
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
// We don't ever need two-phase here since we throw out the result of the coercion.
|
||||
// We also just always set `coerce_never` to true, since this is a heuristic.
|
||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
||||
let coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
|
||||
self.probe(|_| {
|
||||
let Ok(ok) = coerce.coerce(source, target) else {
|
||||
// Make sure to structurally resolve the types, since we use
|
||||
// the `TyKind`s heavily in coercion.
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let structurally_resolve = |ty| {
|
||||
let ty = self.shallow_resolve(ty);
|
||||
if self.next_trait_solver()
|
||||
&& let ty::Alias(..) = ty.kind()
|
||||
{
|
||||
ocx.structurally_normalize(&cause, self.param_env, ty)
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
};
|
||||
let Ok(expr_ty) = structurally_resolve(expr_ty) else {
|
||||
return false;
|
||||
};
|
||||
let Ok(target_ty) = structurally_resolve(target_ty) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Ok(ok) = coerce.coerce(expr_ty, target_ty) else {
|
||||
return false;
|
||||
};
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
ocx.register_obligations(ok.obligations);
|
||||
ocx.select_where_possible().is_empty()
|
||||
})
|
||||
|
@ -1370,7 +1388,7 @@ pub fn can_coerce<'tcx>(
|
|||
) -> bool {
|
||||
let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id);
|
||||
let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id);
|
||||
fn_ctxt.can_coerce(ty, output_ty)
|
||||
fn_ctxt.may_coerce(ty, output_ty)
|
||||
}
|
||||
|
||||
/// CoerceMany encapsulates the pattern you should use when you have
|
||||
|
|
|
@ -1330,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {
|
||||
let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());
|
||||
let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());
|
||||
self.can_coerce(rhs, lhs)
|
||||
self.may_coerce(rhs, lhs)
|
||||
};
|
||||
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
|
||||
let (applicability, eq) = if self.may_coerce(rhs_ty, lhs_ty) {
|
||||
(Applicability::MachineApplicable, true)
|
||||
} else if refs_can_coerce(rhs_ty, lhs_ty) {
|
||||
// The lhs and rhs are likely missing some references in either side. Subsequent
|
||||
|
@ -1349,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let actual_lhs_ty = self.check_expr(rhs_expr);
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.can_coerce(rhs_ty, actual_lhs_ty)
|
||||
self.may_coerce(rhs_ty, actual_lhs_ty)
|
||||
|| refs_can_coerce(rhs_ty, actual_lhs_ty),
|
||||
)
|
||||
} else if let ExprKind::Binary(
|
||||
|
@ -1363,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let actual_rhs_ty = self.check_expr(lhs_expr);
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.can_coerce(actual_rhs_ty, lhs_ty)
|
||||
self.may_coerce(actual_rhs_ty, lhs_ty)
|
||||
|| refs_can_coerce(actual_rhs_ty, lhs_ty),
|
||||
)
|
||||
} else {
|
||||
|
@ -1414,7 +1414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.param_env,
|
||||
)
|
||||
.may_apply();
|
||||
if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
|
||||
if lhs_deref_ty_is_sized && self.may_coerce(rhs_ty, lhs_deref_ty) {
|
||||
err.span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
"consider dereferencing here to assign to the mutably borrowed value",
|
||||
|
|
|
@ -658,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(input_types.iter())
|
||||
.all(|(expected, found)| self.can_coerce(*expected, *found))
|
||||
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
|
@ -722,7 +722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
|
||||
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
|
||||
let can_coerce = self.can_coerce(arg_ty, coerced_ty);
|
||||
let can_coerce = self.may_coerce(arg_ty, coerced_ty);
|
||||
if !can_coerce {
|
||||
return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts(
|
||||
ty::error::ExpectedFound::new(true, coerced_ty, arg_ty),
|
||||
|
@ -802,7 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
|
||||
),
|
||||
) {
|
||||
if !self.can_coerce(provided_ty, *expected_ty) {
|
||||
if !self.may_coerce(provided_ty, *expected_ty) {
|
||||
satisfied = false;
|
||||
break;
|
||||
}
|
||||
|
@ -1023,7 +1023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all(
|
||||
|((expected_ty, _), (provided_ty, _))| {
|
||||
!provided_ty.references_error()
|
||||
&& self.can_coerce(*provided_ty, *expected_ty)
|
||||
&& self.may_coerce(*provided_ty, *expected_ty)
|
||||
},
|
||||
)
|
||||
};
|
||||
|
@ -1114,7 +1114,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
None,
|
||||
Some(trace.values),
|
||||
e,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
@ -2124,7 +2123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let expr_ty = self.typeck_results.borrow().expr_ty(expr);
|
||||
let return_ty = fn_sig.output();
|
||||
if !matches!(expr.kind, hir::ExprKind::Ret(..))
|
||||
&& self.can_coerce(expr_ty, return_ty)
|
||||
&& self.may_coerce(expr_ty, return_ty)
|
||||
{
|
||||
found_semi = true;
|
||||
}
|
||||
|
|
|
@ -261,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
|
||||
expr.kind
|
||||
&& let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
|
||||
&& self.can_coerce(recv_ty, expected)
|
||||
&& self.may_coerce(recv_ty, expected)
|
||||
&& let name = method.name.as_str()
|
||||
&& (name.starts_with("to_") || name.starts_with("as_") || name == "into")
|
||||
{
|
||||
|
@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return true;
|
||||
}
|
||||
|
||||
if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
||||
if self.suggest_fn_call(err, expr, found, |output| self.may_coerce(output, expected))
|
||||
&& let ty::FnDef(def_id, ..) = *found.kind()
|
||||
&& let Some(sp) = self.tcx.hir().span_if_local(def_id)
|
||||
{
|
||||
|
@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
|
||||
return false;
|
||||
}
|
||||
if self.can_coerce(Ty::new_box(self.tcx, found), expected) {
|
||||
if self.may_coerce(Ty::new_box(self.tcx, found), expected) {
|
||||
let suggest_boxing = match found.kind() {
|
||||
ty::Tuple(tuple) if tuple.is_empty() => {
|
||||
errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
|
||||
|
@ -663,7 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
match expected.kind() {
|
||||
ty::Adt(def, _) if Some(def.did()) == pin_did => {
|
||||
if self.can_coerce(pin_box_found, expected) {
|
||||
if self.may_coerce(pin_box_found, expected) {
|
||||
debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
|
||||
match found.kind() {
|
||||
ty::Adt(def, _) if def.is_box() => {
|
||||
|
@ -689,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
true
|
||||
} else if self.can_coerce(pin_found, expected) {
|
||||
} else if self.may_coerce(pin_found, expected) {
|
||||
match found.kind() {
|
||||
ty::Adt(def, _) if def.is_box() => {
|
||||
err.help("use `Box::pin`");
|
||||
|
@ -701,7 +701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
}
|
||||
ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => {
|
||||
ty::Adt(def, _) if def.is_box() && self.may_coerce(box_found, expected) => {
|
||||
// Check if the parent expression is a call to Pin::new. If it
|
||||
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
|
||||
// can suggest Box::pin.
|
||||
|
@ -884,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let ty = Binder::bind_with_vars(ty, bound_vars);
|
||||
let ty = self.normalize(hir_ty.span, ty);
|
||||
let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
|
||||
if self.can_coerce(expected, ty) {
|
||||
if self.may_coerce(expected, ty) {
|
||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||
span: hir_ty.span,
|
||||
expected,
|
||||
|
@ -1141,12 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::Asyncness::No => ty,
|
||||
};
|
||||
let ty = self.normalize(expr.span, ty);
|
||||
self.can_coerce(found, ty)
|
||||
self.may_coerce(found, ty)
|
||||
}
|
||||
hir::FnRetTy::DefaultReturn(_) if in_closure => {
|
||||
self.ret_coercion.as_ref().map_or(false, |ret| {
|
||||
let ret_ty = ret.borrow().expected_ty();
|
||||
self.can_coerce(found, ret_ty)
|
||||
self.may_coerce(found, ret_ty)
|
||||
})
|
||||
}
|
||||
_ => false,
|
||||
|
@ -1510,7 +1510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
provided_ty
|
||||
};
|
||||
|
||||
if !self.can_coerce(expected_ty, dummy_ty) {
|
||||
if !self.may_coerce(expected_ty, dummy_ty) {
|
||||
return;
|
||||
}
|
||||
let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
|
||||
|
@ -1534,7 +1534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_ty: Ty<'tcx>,
|
||||
) {
|
||||
if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() {
|
||||
if self.can_coerce(blk_ty, *elem_ty)
|
||||
if self.may_coerce(blk_ty, *elem_ty)
|
||||
&& blk.stmts.is_empty()
|
||||
&& blk.rules == hir::BlockCheckMode::DefaultBlock
|
||||
{
|
||||
|
@ -1744,7 +1744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if item_ty.has_param() {
|
||||
return false;
|
||||
}
|
||||
if self.can_coerce(item_ty, expected_ty) {
|
||||
if self.may_coerce(item_ty, expected_ty) {
|
||||
err.span_suggestion_verbose(
|
||||
segment.ident.span,
|
||||
format!("try referring to the associated const `{capitalized_name}` instead",),
|
||||
|
@ -1804,7 +1804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
|
||||
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
|
||||
// Check that we're in fact trying to clone into the expected type
|
||||
&& self.can_coerce(*pointee_ty, expected_ty)
|
||||
&& self.may_coerce(*pointee_ty, expected_ty)
|
||||
&& let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
|
||||
// And the expected type doesn't implement `Clone`
|
||||
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
|
||||
|
@ -2022,7 +2022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
return false;
|
||||
};
|
||||
if is_ctor || !self.can_coerce(args.type_at(0), expected) {
|
||||
if is_ctor || !self.may_coerce(args.type_at(0), expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2293,7 +2293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
|
||||
|
||||
let sole_field_ty = sole_field.ty(self.tcx, args);
|
||||
if self.can_coerce(expr_ty, sole_field_ty) {
|
||||
if self.may_coerce(expr_ty, sole_field_ty) {
|
||||
let variant_path =
|
||||
with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
|
||||
// FIXME #56861: DRYer prelude filtering
|
||||
|
@ -2401,7 +2401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let int_type = args.type_at(0);
|
||||
if !self.can_coerce(expr_ty, int_type) {
|
||||
if !self.may_coerce(expr_ty, int_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2585,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
|
||||
}
|
||||
};
|
||||
if self.can_coerce(ref_ty, expected) {
|
||||
if self.may_coerce(ref_ty, expected) {
|
||||
let mut sugg_sp = sp;
|
||||
if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind {
|
||||
let clone_trait =
|
||||
|
|
|
@ -1934,7 +1934,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(args.into_iter())
|
||||
.all(|(expected, found)| self.can_coerce(*expected, *found))
|
||||
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == args.len()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
|
@ -4148,7 +4148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return false;
|
||||
};
|
||||
|
||||
if !self.can_coerce(output, expected) {
|
||||
if !self.may_coerce(output, expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1780,7 +1780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else if inexistent_fields.len() == 1 {
|
||||
match pat_field.pat.kind {
|
||||
PatKind::Lit(expr)
|
||||
if !self.can_coerce(
|
||||
if !self.may_coerce(
|
||||
self.typeck_results.borrow().expr_ty(expr),
|
||||
self.field_ty(field.span, field_def, args),
|
||||
) => {}
|
||||
|
|
|
@ -595,6 +595,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
&self,
|
||||
pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
|
||||
) -> bool {
|
||||
let pred: ty::Predicate<'tcx> = pred.upcast(self.tcx);
|
||||
|
||||
// We sometimes have to use `defining_opaque_types` for predicates
|
||||
// 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 opaque
|
||||
// types have been revealed at this point.
|
||||
if pred.has_opaque_types() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let infcx = self.tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligation(Obligation::new(
|
||||
|
|
|
@ -2302,7 +2302,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
})),
|
||||
terr,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
diag.emit();
|
||||
self.abort.set(true);
|
||||
|
|
|
@ -1127,18 +1127,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
/// the message in `secondary_span` as the primary label, and apply the message that would
|
||||
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
|
||||
/// E0271, like `tests/ui/issues/issue-39970.stderr`.
|
||||
#[instrument(
|
||||
level = "debug",
|
||||
skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
|
||||
)]
|
||||
#[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))]
|
||||
pub fn note_type_err(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
secondary_span: Option<(Span, Cow<'static, str>)>,
|
||||
secondary_span: Option<(Span, Cow<'static, str>, bool)>,
|
||||
mut values: Option<ValuePairs<'tcx>>,
|
||||
terr: TypeError<'tcx>,
|
||||
swap_secondary_and_primary: bool,
|
||||
prefer_label: bool,
|
||||
) {
|
||||
let span = cause.span();
|
||||
|
@ -1304,7 +1300,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
diag.span_note(span, msg);
|
||||
}
|
||||
};
|
||||
if let Some((sp, msg)) = secondary_span {
|
||||
if let Some((secondary_span, secondary_msg, swap_secondary_and_primary)) = secondary_span {
|
||||
if swap_secondary_and_primary {
|
||||
let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||
expected, ..
|
||||
|
@ -1314,11 +1310,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
terr.to_string(self.tcx)
|
||||
};
|
||||
label_or_note(sp, terr);
|
||||
label_or_note(span, msg);
|
||||
label_or_note(secondary_span, terr);
|
||||
label_or_note(span, secondary_msg);
|
||||
} else {
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
label_or_note(sp, msg);
|
||||
label_or_note(secondary_span, secondary_msg);
|
||||
}
|
||||
} else if let Some(values) = values
|
||||
&& let Some((e, f)) = values.ty()
|
||||
|
@ -1788,7 +1784,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
self.type_error_additional_suggestions(&trace, terr),
|
||||
);
|
||||
let mut diag = self.dcx().create_err(failure_code);
|
||||
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
|
||||
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false);
|
||||
diag
|
||||
}
|
||||
|
||||
|
|
|
@ -710,7 +710,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
None,
|
||||
TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
diag
|
||||
}
|
||||
|
@ -1435,6 +1434,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
cx.into_buffer()
|
||||
}
|
||||
))),
|
||||
true,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -1452,7 +1452,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
))
|
||||
}),
|
||||
err,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
self.note_obligation_cause(&mut diag, obligation);
|
||||
|
|
|
@ -1028,7 +1028,7 @@ impl ProjectionElem {
|
|||
ProjectionElem::Field(_idx, fty) => Ok(*fty),
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
Self::subslice_ty(ty, from, to, from_end)
|
||||
Self::subslice_ty(ty, *from, *to, *from_end)
|
||||
}
|
||||
ProjectionElem::Downcast(_) => Ok(ty),
|
||||
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
|
||||
|
@ -1039,13 +1039,13 @@ impl ProjectionElem {
|
|||
ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
|
||||
}
|
||||
|
||||
fn subslice_ty(ty: Ty, from: &u64, to: &u64, from_end: &bool) -> Result<Ty, Error> {
|
||||
fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
|
||||
let ty_kind = ty.kind();
|
||||
match ty_kind {
|
||||
TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
|
||||
TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
|
||||
inner,
|
||||
to.checked_sub(*from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
|
||||
to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
|
||||
),
|
||||
TyKind::RigidTy(RigidTy::Array(inner, size)) => {
|
||||
let size = size.eval_target_usize()?;
|
||||
|
|
|
@ -477,7 +477,7 @@ pub struct PlaceRef<'a> {
|
|||
pub projection: &'a [ProjectionElem],
|
||||
}
|
||||
|
||||
impl<'a> PlaceRef<'a> {
|
||||
impl PlaceRef<'_> {
|
||||
/// Get the type of this place.
|
||||
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
|
||||
self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?))
|
||||
|
|
|
@ -196,39 +196,40 @@ where
|
|||
}
|
||||
|
||||
macro_rules! floating {
|
||||
($ty:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_general_debug(fmt, self)
|
||||
($($ty:ident)*) => {
|
||||
$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_general_debug(fmt, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Display for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_decimal_display(fmt, self)
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Display for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_decimal_display(fmt, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl LowerExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_exponential_common(fmt, self, false)
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl LowerExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_exponential_common(fmt, self, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl UpperExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_exponential_common(fmt, self, true)
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl UpperExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
|
||||
float_to_exponential_common(fmt, self, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
floating! { f32 }
|
||||
floating! { f64 }
|
||||
floating! { f32 f64 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for f16 {
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
use crate::fmt::{Debug, Formatter, Result};
|
||||
|
||||
macro_rules! floating {
|
||||
($ty:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for $ty {
|
||||
#[inline]
|
||||
fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
|
||||
panic!("floating point support is turned off");
|
||||
($($ty:ident)*) => {
|
||||
$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for $ty {
|
||||
#[inline]
|
||||
fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
|
||||
panic!("floating point fmt support is turned off");
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
floating! { f16 }
|
||||
floating! { f32 }
|
||||
floating! { f64 }
|
||||
floating! { f128 }
|
||||
floating! { f16 f32 f64 f128 }
|
||||
|
|
|
@ -20,33 +20,22 @@ trait DisplayInt:
|
|||
|
||||
macro_rules! impl_int {
|
||||
($($t:ident)*) => (
|
||||
$(impl DisplayInt for $t {
|
||||
fn zero() -> Self { 0 }
|
||||
fn from_u8(u: u8) -> Self { u as Self }
|
||||
fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
fn to_u32(&self) -> u32 { *self as u32 }
|
||||
fn to_u64(&self) -> u64 { *self as u64 }
|
||||
fn to_u128(&self) -> u128 { *self as u128 }
|
||||
})*
|
||||
)
|
||||
}
|
||||
macro_rules! impl_uint {
|
||||
($($t:ident)*) => (
|
||||
$(impl DisplayInt for $t {
|
||||
fn zero() -> Self { 0 }
|
||||
fn from_u8(u: u8) -> Self { u as Self }
|
||||
fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
fn to_u32(&self) -> u32 { *self as u32 }
|
||||
fn to_u64(&self) -> u64 { *self as u64 }
|
||||
fn to_u128(&self) -> u128 { *self as u128 }
|
||||
})*
|
||||
$(impl DisplayInt for $t {
|
||||
fn zero() -> Self { 0 }
|
||||
fn from_u8(u: u8) -> Self { u as Self }
|
||||
fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
fn to_u32(&self) -> u32 { *self as u32 }
|
||||
fn to_u64(&self) -> u64 { *self as u64 }
|
||||
fn to_u128(&self) -> u128 { *self as u128 }
|
||||
})*
|
||||
)
|
||||
}
|
||||
|
||||
impl_int! { i8 i16 i32 i64 i128 isize }
|
||||
impl_uint! { u8 u16 u32 u64 u128 usize }
|
||||
impl_int! {
|
||||
i8 i16 i32 i64 i128 isize
|
||||
u8 u16 u32 u64 u128 usize
|
||||
}
|
||||
|
||||
/// A type that represents a specific radix
|
||||
///
|
||||
|
@ -178,26 +167,25 @@ integer! { i16, u16 }
|
|||
integer! { i32, u32 }
|
||||
integer! { i64, u64 }
|
||||
integer! { i128, u128 }
|
||||
macro_rules! debug {
|
||||
($($T:ident)*) => {$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for $T {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if f.debug_lower_hex() {
|
||||
fmt::LowerHex::fmt(self, f)
|
||||
} else if f.debug_upper_hex() {
|
||||
fmt::UpperHex::fmt(self, f)
|
||||
} else {
|
||||
fmt::Display::fmt(self, f)
|
||||
|
||||
macro_rules! impl_Debug {
|
||||
($($T:ident)*) => {
|
||||
$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for $T {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if f.debug_lower_hex() {
|
||||
fmt::LowerHex::fmt(self, f)
|
||||
} else if f.debug_upper_hex() {
|
||||
fmt::UpperHex::fmt(self, f)
|
||||
} else {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
debug! {
|
||||
i8 i16 i32 i64 i128 isize
|
||||
u8 u16 u32 u64 u128 usize
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
// 2 digit decimal look up table
|
||||
|
@ -521,6 +509,11 @@ macro_rules! impl_Exp {
|
|||
};
|
||||
}
|
||||
|
||||
impl_Debug! {
|
||||
i8 i16 i32 i64 i128 isize
|
||||
u8 u16 u32 u64 u128 usize
|
||||
}
|
||||
|
||||
// Include wasm32 in here since it doesn't reflect the native pointer size, and
|
||||
// often cares strongly about getting a smaller code size.
|
||||
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
|
||||
|
|
|
@ -1228,15 +1228,14 @@ impl Attributes {
|
|||
for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
|
||||
if let Some(values) = attr.meta_item_list() {
|
||||
for l in values {
|
||||
match l.lit().unwrap().kind {
|
||||
ast::LitKind::Str(s, _) => {
|
||||
aliases.insert(s);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
if let Some(lit) = l.lit()
|
||||
&& let ast::LitKind::Str(s, _) = lit.kind
|
||||
{
|
||||
aliases.insert(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aliases.insert(attr.value_str().unwrap());
|
||||
} else if let Some(value) = attr.value_str() {
|
||||
aliases.insert(value);
|
||||
}
|
||||
}
|
||||
aliases.into_iter().collect::<Vec<_>>().into()
|
||||
|
|
|
@ -29,8 +29,9 @@ use crate::clean::inline::build_external_trait;
|
|||
use crate::clean::{self, ItemId};
|
||||
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::passes;
|
||||
use crate::passes::Condition::*;
|
||||
use crate::passes::{self};
|
||||
use crate::passes::collect_intra_doc_links::LinkCollector;
|
||||
|
||||
pub(crate) struct DocContext<'tcx> {
|
||||
pub(crate) tcx: TyCtxt<'tcx>,
|
||||
|
@ -427,6 +428,9 @@ pub(crate) fn run_global_ctxt(
|
|||
|
||||
info!("Executing passes");
|
||||
|
||||
let mut visited = FxHashMap::default();
|
||||
let mut ambiguous = FxIndexMap::default();
|
||||
|
||||
for p in passes::defaults(show_coverage) {
|
||||
let run = match p.condition {
|
||||
Always => true,
|
||||
|
@ -436,18 +440,30 @@ pub(crate) fn run_global_ctxt(
|
|||
};
|
||||
if run {
|
||||
debug!("running pass {}", p.pass.name);
|
||||
krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
|
||||
if let Some(run_fn) = p.pass.run {
|
||||
krate = tcx.sess.time(p.pass.name, || run_fn(krate, &mut ctxt));
|
||||
} else {
|
||||
let (k, LinkCollector { visited_links, ambiguous_links, .. }) =
|
||||
passes::collect_intra_doc_links::collect_intra_doc_links(krate, &mut ctxt);
|
||||
krate = k;
|
||||
visited = visited_links;
|
||||
ambiguous = ambiguous_links;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
|
||||
|
||||
krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate));
|
||||
|
||||
let mut collector =
|
||||
LinkCollector { cx: &mut ctxt, visited_links: visited, ambiguous_links: ambiguous };
|
||||
collector.resolve_ambiguities();
|
||||
|
||||
if let Some(guar) = tcx.dcx().has_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate));
|
||||
|
||||
Ok((krate, ctxt.render_options, ctxt.cache))
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::visit::DocVisitor;
|
|||
|
||||
pub(crate) const CALCULATE_DOC_COVERAGE: Pass = Pass {
|
||||
name: "calculate-doc-coverage",
|
||||
run: calculate_doc_coverage,
|
||||
run: Some(calculate_doc_coverage),
|
||||
description: "counts the number of items with and without documentation",
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::visit::DocVisitor;
|
|||
|
||||
pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass {
|
||||
name: "check_doc_test_visibility",
|
||||
run: check_doc_test_visibility,
|
||||
run: Some(check_doc_test_visibility),
|
||||
description: "run various visibility-related lints on doctests",
|
||||
};
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ use std::ops::Range;
|
|||
|
||||
use pulldown_cmark::LinkType;
|
||||
use rustc_ast::util::comments::may_have_doc_links;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage};
|
||||
use rustc_hir::def::Namespace::*;
|
||||
use rustc_hir::def::{DefKind, Namespace, PerNS};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
|
||||
use rustc_hir::{Mutability, Safety};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
|
@ -30,23 +30,27 @@ use smallvec::{SmallVec, smallvec};
|
|||
use tracing::{debug, info, instrument, trace};
|
||||
|
||||
use crate::clean::utils::find_nearest_parent_module;
|
||||
use crate::clean::{self, Crate, Item, ItemLink, PrimitiveType};
|
||||
use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType};
|
||||
use crate::core::DocContext;
|
||||
use crate::html::markdown::{MarkdownLink, MarkdownLinkRange, markdown_links};
|
||||
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
|
||||
use crate::passes::Pass;
|
||||
use crate::visit::DocVisitor;
|
||||
|
||||
pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
|
||||
name: "collect-intra-doc-links",
|
||||
run: collect_intra_doc_links,
|
||||
description: "resolves intra-doc links",
|
||||
};
|
||||
pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass =
|
||||
Pass { name: "collect-intra-doc-links", run: None, description: "resolves intra-doc links" };
|
||||
|
||||
fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
||||
let mut collector = LinkCollector { cx, visited_links: FxHashMap::default() };
|
||||
pub(crate) fn collect_intra_doc_links<'a, 'tcx>(
|
||||
krate: Crate,
|
||||
cx: &'a mut DocContext<'tcx>,
|
||||
) -> (Crate, LinkCollector<'a, 'tcx>) {
|
||||
let mut collector = LinkCollector {
|
||||
cx,
|
||||
visited_links: FxHashMap::default(),
|
||||
ambiguous_links: FxIndexMap::default(),
|
||||
};
|
||||
collector.visit_crate(&krate);
|
||||
krate
|
||||
(krate, collector)
|
||||
}
|
||||
|
||||
fn filter_assoc_items_by_name_and_namespace<'a>(
|
||||
|
@ -61,7 +65,7 @@ fn filter_assoc_items_by_name_and_namespace<'a>(
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
|
||||
enum Res {
|
||||
pub(crate) enum Res {
|
||||
Def(DefKind, DefId),
|
||||
Primitive(PrimitiveType),
|
||||
}
|
||||
|
@ -234,7 +238,7 @@ impl UrlFragment {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
struct ResolutionInfo {
|
||||
pub(crate) struct ResolutionInfo {
|
||||
item_id: DefId,
|
||||
module_id: DefId,
|
||||
dis: Option<Disambiguator>,
|
||||
|
@ -243,18 +247,64 @@ struct ResolutionInfo {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DiagnosticInfo<'a> {
|
||||
pub(crate) struct DiagnosticInfo<'a> {
|
||||
item: &'a Item,
|
||||
dox: &'a str,
|
||||
ori_link: &'a str,
|
||||
link_range: MarkdownLinkRange,
|
||||
}
|
||||
|
||||
struct LinkCollector<'a, 'tcx> {
|
||||
cx: &'a mut DocContext<'tcx>,
|
||||
pub(crate) struct OwnedDiagnosticInfo {
|
||||
item: Item,
|
||||
dox: String,
|
||||
ori_link: String,
|
||||
link_range: MarkdownLinkRange,
|
||||
}
|
||||
|
||||
impl From<DiagnosticInfo<'_>> for OwnedDiagnosticInfo {
|
||||
fn from(f: DiagnosticInfo<'_>) -> Self {
|
||||
Self {
|
||||
item: f.item.clone(),
|
||||
dox: f.dox.to_string(),
|
||||
ori_link: f.ori_link.to_string(),
|
||||
link_range: f.link_range.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OwnedDiagnosticInfo {
|
||||
pub(crate) fn into_info(&self) -> DiagnosticInfo<'_> {
|
||||
DiagnosticInfo {
|
||||
item: &self.item,
|
||||
ori_link: &self.ori_link,
|
||||
dox: &self.dox,
|
||||
link_range: self.link_range.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LinkCollector<'a, 'tcx> {
|
||||
pub(crate) cx: &'a mut DocContext<'tcx>,
|
||||
/// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link.
|
||||
/// The link will be `None` if it could not be resolved (i.e. the error was cached).
|
||||
visited_links: FxHashMap<ResolutionInfo, Option<(Res, Option<UrlFragment>)>>,
|
||||
pub(crate) visited_links: FxHashMap<ResolutionInfo, Option<(Res, Option<UrlFragment>)>>,
|
||||
/// According to `rustc_resolve`, these links are ambiguous.
|
||||
///
|
||||
/// However, we cannot link to an item that has been stripped from the documentation. If all
|
||||
/// but one of the "possibilities" are stripped, then there is no real ambiguity. To determine
|
||||
/// if an ambiguity is real, we delay resolving them until after `Cache::populate`, then filter
|
||||
/// every item that doesn't have a cached path.
|
||||
///
|
||||
/// We could get correct results by simply delaying everything. This would have fewer happy
|
||||
/// codepaths, but we want to distinguish different kinds of error conditions, and this is easy
|
||||
/// to do by resolving links as soon as possible.
|
||||
pub(crate) ambiguous_links: FxIndexMap<(ItemId, String), Vec<AmbiguousLinks>>,
|
||||
}
|
||||
|
||||
pub(crate) struct AmbiguousLinks {
|
||||
link_text: Box<str>,
|
||||
diag_info: OwnedDiagnosticInfo,
|
||||
resolved: Vec<(Res, Option<UrlFragment>)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||
|
@ -1001,6 +1051,10 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn save_link(&mut self, item_id: ItemId, link: ItemLink) {
|
||||
self.cx.cache.intra_doc_links.entry(item_id).or_default().insert(link);
|
||||
}
|
||||
|
||||
/// This is the entry point for resolving an intra-doc link.
|
||||
///
|
||||
/// FIXME(jynelson): this is way too many arguments
|
||||
|
@ -1024,7 +1078,7 @@ impl LinkCollector<'_, '_> {
|
|||
pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
|
||||
let disambiguator = *disambiguator;
|
||||
|
||||
let (mut res, fragment) = self.resolve_with_disambiguator_cached(
|
||||
let mut resolved = self.resolve_with_disambiguator_cached(
|
||||
ResolutionInfo {
|
||||
item_id,
|
||||
module_id,
|
||||
|
@ -1040,6 +1094,139 @@ impl LinkCollector<'_, '_> {
|
|||
false,
|
||||
)?;
|
||||
|
||||
if resolved.len() > 1 {
|
||||
let links = AmbiguousLinks {
|
||||
link_text: link_text.clone(),
|
||||
diag_info: diag_info.into(),
|
||||
resolved,
|
||||
};
|
||||
|
||||
self.ambiguous_links
|
||||
.entry((item.item_id, path_str.to_string()))
|
||||
.or_default()
|
||||
.push(links);
|
||||
None
|
||||
} else if let Some((res, fragment)) = resolved.pop() {
|
||||
self.compute_link(res, fragment, path_str, disambiguator, diag_info, link_text)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a link could be generated from the given intra-doc information.
|
||||
///
|
||||
/// This is a very light version of `format::href_with_root_path` since we're only interested
|
||||
/// about whether we can generate a link to an item or not.
|
||||
///
|
||||
/// * If `original_did` is local, then we check if the item is reexported or public.
|
||||
/// * If `original_did` is not local, then we check if the crate it comes from is a direct
|
||||
/// public dependency.
|
||||
fn validate_link(&self, original_did: DefId) -> bool {
|
||||
let tcx = self.cx.tcx;
|
||||
let def_kind = tcx.def_kind(original_did);
|
||||
let did = match def_kind {
|
||||
DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
|
||||
// documented on their parent's page
|
||||
tcx.parent(original_did)
|
||||
}
|
||||
// If this a constructor, we get the parent (either a struct or a variant) and then
|
||||
// generate the link for this item.
|
||||
DefKind::Ctor(..) => return self.validate_link(tcx.parent(original_did)),
|
||||
DefKind::ExternCrate => {
|
||||
// Link to the crate itself, not the `extern crate` item.
|
||||
if let Some(local_did) = original_did.as_local() {
|
||||
tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id()
|
||||
} else {
|
||||
original_did
|
||||
}
|
||||
}
|
||||
_ => original_did,
|
||||
};
|
||||
|
||||
let cache = &self.cx.cache;
|
||||
if !original_did.is_local()
|
||||
&& !cache.effective_visibilities.is_directly_public(tcx, did)
|
||||
&& !cache.document_private
|
||||
&& !cache.primitive_locations.values().any(|&id| id == did)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cache.paths.get(&did).is_some()
|
||||
|| cache.external_paths.get(&did).is_some()
|
||||
|| !did.is_local()
|
||||
}
|
||||
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
pub(crate) fn resolve_ambiguities(&mut self) {
|
||||
let mut ambiguous_links = mem::take(&mut self.ambiguous_links);
|
||||
|
||||
for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() {
|
||||
for info in info_items {
|
||||
info.resolved.retain(|(res, _)| match res {
|
||||
Res::Def(_, def_id) => self.validate_link(*def_id),
|
||||
// Primitive types are always valid.
|
||||
Res::Primitive(_) => true,
|
||||
});
|
||||
let diag_info = info.diag_info.into_info();
|
||||
match info.resolved.len() {
|
||||
1 => {
|
||||
let (res, fragment) = info.resolved.pop().unwrap();
|
||||
if let Some(link) = self.compute_link(
|
||||
res,
|
||||
fragment,
|
||||
path_str,
|
||||
None,
|
||||
diag_info,
|
||||
&info.link_text,
|
||||
) {
|
||||
self.save_link(*item_id, link);
|
||||
}
|
||||
}
|
||||
0 => {
|
||||
report_diagnostic(
|
||||
self.cx.tcx,
|
||||
BROKEN_INTRA_DOC_LINKS,
|
||||
format!("all items matching `{path_str}` are private or doc(hidden)"),
|
||||
&diag_info,
|
||||
|diag, sp, _| {
|
||||
if let Some(sp) = sp {
|
||||
diag.span_label(sp, "unresolved link");
|
||||
} else {
|
||||
diag.note("unresolved link");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let candidates = info
|
||||
.resolved
|
||||
.iter()
|
||||
.map(|(res, fragment)| {
|
||||
let def_id = if let Some(UrlFragment::Item(def_id)) = fragment {
|
||||
Some(*def_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(*res, def_id)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
ambiguity_error(self.cx, &diag_info, path_str, &candidates, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_link(
|
||||
&mut self,
|
||||
mut res: Res,
|
||||
fragment: Option<UrlFragment>,
|
||||
path_str: &str,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
diag_info: DiagnosticInfo<'_>,
|
||||
link_text: &Box<str>,
|
||||
) -> Option<ItemLink> {
|
||||
// Check for a primitive which might conflict with a module
|
||||
// Report the ambiguity and require that the user specify which one they meant.
|
||||
// FIXME: could there ever be a primitive not in the type namespace?
|
||||
|
@ -1055,7 +1242,7 @@ impl LinkCollector<'_, '_> {
|
|||
} else {
|
||||
// `[char]` when a `char` module is in scope
|
||||
let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)];
|
||||
ambiguity_error(self.cx, &diag_info, path_str, candidates);
|
||||
ambiguity_error(self.cx, &diag_info, path_str, candidates, true);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -1085,7 +1272,7 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
|
||||
res.def_id(self.cx.tcx).map(|page_id| ItemLink {
|
||||
link: Box::<str>::from(&*ori_link.link),
|
||||
link: Box::<str>::from(&*diag_info.ori_link),
|
||||
link_text: link_text.clone(),
|
||||
page_id,
|
||||
fragment,
|
||||
|
@ -1107,7 +1294,7 @@ impl LinkCollector<'_, '_> {
|
|||
|
||||
let page_id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
|
||||
Some(ItemLink {
|
||||
link: Box::<str>::from(&*ori_link.link),
|
||||
link: Box::<str>::from(&*diag_info.ori_link),
|
||||
link_text: link_text.clone(),
|
||||
page_id,
|
||||
fragment,
|
||||
|
@ -1220,10 +1407,10 @@ impl LinkCollector<'_, '_> {
|
|||
// If this call is intended to be recoverable, then pass true to silence.
|
||||
// This is only recoverable when path is failed to resolved.
|
||||
recoverable: bool,
|
||||
) -> Option<(Res, Option<UrlFragment>)> {
|
||||
) -> Option<Vec<(Res, Option<UrlFragment>)>> {
|
||||
if let Some(res) = self.visited_links.get(&key) {
|
||||
if res.is_some() || cache_errors {
|
||||
return res.clone();
|
||||
return res.clone().map(|r| vec![r]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1248,13 +1435,14 @@ 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 let [candidate, _candidate2, ..] = *candidates
|
||||
&& !ambiguity_error(self.cx, &diag, &key.path_str, &candidates)
|
||||
{
|
||||
candidates = vec![candidate];
|
||||
if let [candidate, _candidate2, ..] = *candidates {
|
||||
if !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false) {
|
||||
candidates = vec![candidate];
|
||||
}
|
||||
}
|
||||
|
||||
if let &[(res, def_id)] = candidates.as_slice() {
|
||||
let mut out = Vec::with_capacity(candidates.len());
|
||||
for (res, def_id) in candidates {
|
||||
let fragment = match (&key.extra_fragment, def_id) {
|
||||
(Some(_), Some(def_id)) => {
|
||||
report_anchor_conflict(self.cx, diag, def_id);
|
||||
|
@ -1264,15 +1452,14 @@ impl LinkCollector<'_, '_> {
|
|||
(None, Some(def_id)) => Some(UrlFragment::Item(def_id)),
|
||||
(None, None) => None,
|
||||
};
|
||||
let r = Some((res, fragment));
|
||||
self.visited_links.insert(key, r.clone());
|
||||
return r;
|
||||
out.push((res, fragment));
|
||||
}
|
||||
|
||||
if cache_errors {
|
||||
if let [r] = out.as_slice() {
|
||||
self.visited_links.insert(key, Some(r.clone()));
|
||||
} else if cache_errors {
|
||||
self.visited_links.insert(key, None);
|
||||
}
|
||||
None
|
||||
Some(out)
|
||||
}
|
||||
|
||||
/// After parsing the disambiguator, resolve the main part of the link.
|
||||
|
@ -2046,6 +2233,7 @@ fn ambiguity_error(
|
|||
diag_info: &DiagnosticInfo<'_>,
|
||||
path_str: &str,
|
||||
candidates: &[(Res, Option<DefId>)],
|
||||
emit_error: bool,
|
||||
) -> bool {
|
||||
let mut descrs = FxHashSet::default();
|
||||
let kinds = candidates
|
||||
|
@ -2061,6 +2249,8 @@ fn ambiguity_error(
|
|||
// There is no way for users to disambiguate at this point, so better return the first
|
||||
// candidate and not show a warning.
|
||||
return false;
|
||||
} else if !emit_error {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut msg = format!("`{path_str}` is ");
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::visit::DocVisitor;
|
|||
|
||||
pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
|
||||
name: "collect-trait-impls",
|
||||
run: collect_trait_impls,
|
||||
run: Some(collect_trait_impls),
|
||||
description: "retrieves trait impls for items in the crate",
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::core::DocContext;
|
|||
use crate::visit::DocVisitor;
|
||||
|
||||
pub(crate) const RUN_LINTS: Pass =
|
||||
Pass { name: "run-lints", run: run_lints, description: "runs some of rustdoc's lints" };
|
||||
Pass { name: "run-lints", run: Some(run_lints), description: "runs some of rustdoc's lints" };
|
||||
|
||||
struct Linter<'a, 'tcx> {
|
||||
cx: &'a mut DocContext<'tcx>,
|
||||
|
|
|
@ -47,7 +47,7 @@ pub(crate) use self::lint::RUN_LINTS;
|
|||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct Pass {
|
||||
pub(crate) name: &'static str,
|
||||
pub(crate) run: fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate,
|
||||
pub(crate) run: Option<fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate>,
|
||||
pub(crate) description: &'static str,
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::passes::Pass;
|
|||
|
||||
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
|
||||
name: "propagate-doc-cfg",
|
||||
run: propagate_doc_cfg,
|
||||
run: Some(propagate_doc_cfg),
|
||||
description: "propagates `#[doc(cfg(...))]` to child items",
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::passes::Pass;
|
|||
|
||||
pub(crate) const PROPAGATE_STABILITY: Pass = Pass {
|
||||
name: "propagate-stability",
|
||||
run: propagate_stability,
|
||||
run: Some(propagate_stability),
|
||||
description: "propagates stability to child items",
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::passes::Pass;
|
|||
|
||||
pub(crate) const STRIP_ALIASED_NON_LOCAL: Pass = Pass {
|
||||
name: "strip-aliased-non-local",
|
||||
run: strip_aliased_non_local,
|
||||
run: Some(strip_aliased_non_local),
|
||||
description: "strips all non-local private aliased items from the output",
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::passes::{ImplStripper, Pass};
|
|||
|
||||
pub(crate) const STRIP_HIDDEN: Pass = Pass {
|
||||
name: "strip-hidden",
|
||||
run: strip_hidden,
|
||||
run: Some(strip_hidden),
|
||||
description: "strips all `#[doc(hidden)]` items from the output",
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::passes::{ImportStripper, Pass};
|
|||
|
||||
pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass {
|
||||
name: "strip-priv-imports",
|
||||
run: strip_priv_imports,
|
||||
run: Some(strip_priv_imports),
|
||||
description: "strips all private import statements (`use`, `extern crate`) from a crate",
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
|
|||
|
||||
pub(crate) const STRIP_PRIVATE: Pass = Pass {
|
||||
name: "strip-private",
|
||||
run: strip_private,
|
||||
run: Some(strip_private),
|
||||
description: "strips all private items from a crate which cannot be seen externally, \
|
||||
implies strip-priv-imports",
|
||||
};
|
||||
|
|
|
@ -613,26 +613,8 @@ impl Rewrite for ast::GenericBound {
|
|||
ast::GenericBound::Trait(ref poly_trait_ref) => {
|
||||
let snippet = context.snippet(self.span());
|
||||
let has_paren = snippet.starts_with('(') && snippet.ends_with(')');
|
||||
let ast::TraitBoundModifiers {
|
||||
constness,
|
||||
asyncness,
|
||||
polarity,
|
||||
} = poly_trait_ref.modifiers;
|
||||
let mut constness = constness.as_str().to_string();
|
||||
if !constness.is_empty() {
|
||||
constness.push(' ');
|
||||
}
|
||||
let mut asyncness = asyncness.as_str().to_string();
|
||||
if !asyncness.is_empty() {
|
||||
asyncness.push(' ');
|
||||
}
|
||||
let polarity = polarity.as_str();
|
||||
let shape = shape
|
||||
.offset_left(constness.len() + polarity.len())
|
||||
.max_width_error(shape.width, self.span())?;
|
||||
poly_trait_ref
|
||||
.rewrite_result(context, shape)
|
||||
.map(|s| format!("{constness}{asyncness}{polarity}{s}"))
|
||||
.map(|s| if has_paren { format!("({})", s) } else { s })
|
||||
}
|
||||
ast::GenericBound::Use(ref args, span) => {
|
||||
|
@ -756,19 +738,41 @@ impl Rewrite for ast::PolyTraitRef {
|
|||
}
|
||||
|
||||
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
|
||||
if let Some(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params)
|
||||
let (binder, shape) = if let Some(lifetime_str) =
|
||||
rewrite_bound_params(context, shape, &self.bound_generic_params)
|
||||
{
|
||||
// 6 is "for<> ".len()
|
||||
let extra_offset = lifetime_str.len() + 6;
|
||||
let shape = shape
|
||||
.offset_left(extra_offset)
|
||||
.max_width_error(shape.width, self.span)?;
|
||||
let path_str = self.trait_ref.rewrite_result(context, shape)?;
|
||||
|
||||
Ok(format!("for<{lifetime_str}> {path_str}"))
|
||||
(format!("for<{lifetime_str}> "), shape)
|
||||
} else {
|
||||
self.trait_ref.rewrite_result(context, shape)
|
||||
(String::new(), shape)
|
||||
};
|
||||
|
||||
let ast::TraitBoundModifiers {
|
||||
constness,
|
||||
asyncness,
|
||||
polarity,
|
||||
} = self.modifiers;
|
||||
let mut constness = constness.as_str().to_string();
|
||||
if !constness.is_empty() {
|
||||
constness.push(' ');
|
||||
}
|
||||
let mut asyncness = asyncness.as_str().to_string();
|
||||
if !asyncness.is_empty() {
|
||||
asyncness.push(' ');
|
||||
}
|
||||
let polarity = polarity.as_str();
|
||||
let shape = shape
|
||||
.offset_left(constness.len() + polarity.len())
|
||||
.max_width_error(shape.width, self.span)?;
|
||||
|
||||
let path_str = self.trait_ref.rewrite_result(context, shape)?;
|
||||
Ok(format!(
|
||||
"{binder}{constness}{asyncness}{polarity}{path_str}"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// rustfmt-edition: 2018
|
||||
|
||||
fn foo() -> impl async Fn() {}
|
||||
|
||||
fn bar() -> impl for<'a> async Fn(&'a ()) {}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
//@ known-bug: #130921
|
||||
//@ compile-flags: -Zvalidate-mir -Copt-level=0 --crate-type lib
|
||||
|
||||
pub fn hello() -> [impl Sized; 2] {
|
||||
if false {
|
||||
let x = hello();
|
||||
let _: &[i32] = &x;
|
||||
}
|
||||
todo!()
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// This test ensures that ambiguities (not) resolved at a later stage still emit an error.
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Thing {}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[doc(hidden)]
|
||||
pub fn Thing() {}
|
||||
|
||||
/// Do stuff with [`Thing`].
|
||||
//~^ ERROR all items matching `Thing` are private or doc(hidden)
|
||||
pub fn repro(_: Thing) {}
|
|
@ -0,0 +1,14 @@
|
|||
error: all items matching `Thing` are private or doc(hidden)
|
||||
--> $DIR/filter-out-private-2.rs:13:21
|
||||
|
|
||||
LL | /// Do stuff with [`Thing`].
|
||||
| ^^^^^ unresolved link
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/filter-out-private-2.rs:3:9
|
||||
|
|
||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// This test ensures that ambiguities resolved at a later stage still emit an error.
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
pub struct Thing {}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Thing() {}
|
||||
|
||||
/// Do stuff with [`Thing`].
|
||||
//~^ ERROR `Thing` is both a function and a struct
|
||||
pub fn repro(_: Thing) {}
|
|
@ -0,0 +1,22 @@
|
|||
error: `Thing` is both a function and a struct
|
||||
--> $DIR/filter-out-private.rs:11:21
|
||||
|
|
||||
LL | /// Do stuff with [`Thing`].
|
||||
| ^^^^^ ambiguous link
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/filter-out-private.rs:3:9
|
||||
|
|
||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to link to the function, add parentheses
|
||||
|
|
||||
LL | /// Do stuff with [`Thing()`].
|
||||
| ++
|
||||
help: to link to the struct, prefix with `struct@`
|
||||
|
|
||||
LL | /// Do stuff with [`struct@Thing`].
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// This test ensures that private/hidden items don't create ambiguity.
|
||||
// This is a regression test for <https://github.com/rust-lang/rust/issues/130233>.
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
pub struct Thing {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Thing() {}
|
||||
|
||||
pub struct Bar {}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn Bar() {}
|
||||
|
||||
//@ has 'foo/fn.repro.html'
|
||||
//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]//a/@href' 'struct.Thing.html'
|
||||
/// Do stuff with [`Thing`].
|
||||
pub fn repro(_: Thing) {}
|
||||
|
||||
//@ has 'foo/fn.repro2.html'
|
||||
//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]//a/@href' 'struct.Bar.html'
|
||||
/// Do stuff with [`Bar`].
|
||||
pub fn repro2(_: Bar) {}
|
|
@ -9,6 +9,7 @@
|
|||
//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written).
|
||||
//@ needs-unwind
|
||||
//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes
|
||||
//@ ignore-emscripten Requires custom symbolization code
|
||||
//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs
|
||||
//@ aux-crate: auxiliary=dylib-dep-helper-aux.rs
|
||||
//@ run-pass
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only
|
||||
//@ ignore-android FIXME #17520
|
||||
//@ ignore-fuchsia Backtraces not symbolized
|
||||
//@ ignore-emscripten Requires custom symbolization code
|
||||
//@ needs-unwind
|
||||
//@ aux-build: line-tables-only-helper.rs
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
fn hello() -> &'static [impl Sized; 0] {
|
||||
if false {
|
||||
let x = hello();
|
||||
let _: &[i32] = x;
|
||||
}
|
||||
&[]
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,19 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
|
||||
trait Mirror {
|
||||
type Assoc;
|
||||
}
|
||||
impl<T> Mirror for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
fn arg() -> &'static [i32; 1] { todo!() }
|
||||
|
||||
fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
|
||||
|
||||
fn main() {
|
||||
// Should suggest to reverse the args...
|
||||
// but if we don't normalize the expected, then we don't.
|
||||
arg_error((), || ());
|
||||
//~^ ERROR arguments to this function are incorrect
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
error[E0308]: arguments to this function are incorrect
|
||||
--> $DIR/coerce-in-may-coerce.rs:17:5
|
||||
|
|
||||
LL | arg_error((), || ());
|
||||
| ^^^^^^^^^ -- ----- expected `()`, found `{closure@$DIR/coerce-in-may-coerce.rs:17:19: 17:21}`
|
||||
| |
|
||||
| expected `<fn() as Mirror>::Assoc`, found `()`
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/coerce-in-may-coerce.rs:12:4
|
||||
|
|
||||
LL | fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
|
||||
| ^^^^^^^^^ -------------------------- -----
|
||||
help: swap these arguments
|
||||
|
|
||||
LL | arg_error(|| (), ());
|
||||
| ~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -1,3 +1,15 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:11:5
|
||||
|
|
||||
LL | fn reify_as_tait() -> Thunk<Tait> {
|
||||
| ----------- expected `Thunk<_>` because of return type
|
||||
LL |
|
||||
LL | Thunk::new(|cont| cont)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()`
|
||||
|
|
||||
= note: expected struct `Thunk<_>`
|
||||
found unit type `()`
|
||||
|
||||
error[E0277]: expected a `FnOnce()` closure, found `()`
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:11:23
|
||||
|
|
||||
|
@ -12,19 +24,13 @@ error[E0277]: expected a `FnOnce()` closure, found `()`
|
|||
|
|
||||
LL | fn reify_as_tait() -> Thunk<Tait> {
|
||||
| ^^^^^^^^^^^ expected an `FnOnce()` closure, found `()`
|
||||
LL |
|
||||
LL | Thunk::new(|cont| cont)
|
||||
| ----------------------- return type was inferred to be `{type error}` here
|
||||
|
|
||||
= help: the trait `FnOnce()` is not implemented for `()`
|
||||
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:11:5
|
||||
|
|
||||
LL | Thunk::new(|cont| cont)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()`
|
||||
|
|
||||
= note: expected struct `Thunk<_>`
|
||||
found unit type `()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
|
|
Loading…
Reference in New Issue