Skip to content

Rollup of 9 pull requests #123484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Apr 5, 2024
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8f5a28e
Require Pointee::Metadata to be Freeze
stepancheg Mar 29, 2024
2edc54c
Default to light theme is JS is enabled but not working
GuillaumeGomez Apr 3, 2024
8f9d93b
Add GUI test to ensure there is always a theme applied if JS is disabled
GuillaumeGomez Apr 3, 2024
2815edc
Update `rustdoc_css_themes.rs` to take into account new selectors
GuillaumeGomez Apr 3, 2024
f6b97ef
Manually run `clang-format` on `CoverageMappingWrapper.cpp`
Zalathar Apr 3, 2024
d99c775
unconstrained `NormalizesTo` term for opaques
lcnr Apr 2, 2024
92b280c
normalizes-to change from '1' to '0 to inf' steps
lcnr Apr 2, 2024
17475de
hir: Use `ItemLocalId` in a couple more places
petrochenkov Apr 4, 2024
612acf8
rustdoc prioritise cargo doc: suggestions applied
harryhanYuhao Apr 4, 2024
6f17b7f
Rename HAS_PROJECTIONS to HAS_ALIASES etc.
fmease Apr 4, 2024
f2ff9c9
Update browser-ui-test version to 0.17.1
GuillaumeGomez Apr 4, 2024
a815b97
Add regression test to ensure that even if JS is enabled but not work…
GuillaumeGomez Apr 4, 2024
9444ca3
do not ICE in forced ambiguity if we get an error
lcnr Apr 4, 2024
b53a0f2
CFI: Add test for `call_once` addr taken
maurer Apr 4, 2024
de2cb0d
Rollup merge of #123206 - stepancheg:pointee-metadata-freeze, r=Amanieu
jhpratt Apr 5, 2024
fcb0e9d
Rollup merge of #123363 - lcnr:normalizes-to-zero-to-inf, r=BoxyUwU
jhpratt Apr 5, 2024
ac29872
Rollup merge of #123407 - GuillaumeGomez:js-failed-theme, r=notriddle
jhpratt Apr 5, 2024
50603cb
Rollup merge of #123417 - harryhanYuhao:master, r=GuillaumeGomez
jhpratt Apr 5, 2024
daef0fd
Rollup merge of #123437 - Zalathar:clang-format, r=cuviper
jhpratt Apr 5, 2024
929e0db
Rollup merge of #123454 - petrochenkov:zeroindex2, r=fmease
jhpratt Apr 5, 2024
58eb6e5
Rollup merge of #123464 - fmease:rn-has-proj-to-has-aliases, r=compil…
jhpratt Apr 5, 2024
e01d3e0
Rollup merge of #123477 - lcnr:forced_ambig-no-ice, r=compiler-errors
jhpratt Apr 5, 2024
e8b0c30
Rollup merge of #123478 - maurer:cfi-call-once-addr-taken, r=compiler…
jhpratt Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ struct NodeCollector<'a, 'hir> {
parenting: LocalDefIdMap<ItemLocalId>,

/// The parent of this node
parent_node: hir::ItemLocalId,
parent_node: ItemLocalId,

owner: OwnerId,
}
@@ -31,17 +31,16 @@ pub(super) fn index_hir<'hir>(
bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
num_nodes: usize,
) -> (IndexVec<ItemLocalId, ParentedNode<'hir>>, LocalDefIdMap<ItemLocalId>) {
let zero_id = ItemLocalId::ZERO;
let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) };
let err_node = ParentedNode { parent: ItemLocalId::ZERO, node: Node::Err(item.span()) };
let mut nodes = IndexVec::from_elem_n(err_node, num_nodes);
// This node's parent should never be accessed: the owner's parent is computed by the
// hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
// used.
nodes[zero_id] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() };
nodes[ItemLocalId::ZERO] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() };
let mut collector = NodeCollector {
tcx,
owner: item.def_id(),
parent_node: zero_id,
parent_node: ItemLocalId::ZERO,
nodes,
bodies,
parenting: Default::default(),
@@ -112,7 +111,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
}

fn insert_nested(&mut self, item: LocalDefId) {
if self.parent_node.as_u32() != 0 {
if self.parent_node != ItemLocalId::ZERO {
self.parenting.insert(item, self.parent_node);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -461,7 +461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
where
T: TypeVisitable<TyCtxt<'tcx>>,
{
t.has_free_regions() || t.has_projections() || t.has_infer_types()
t.has_free_regions() || t.has_aliases() || t.has_infer_types()
}

pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
48 changes: 20 additions & 28 deletions compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "LLVMWrapper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ADT/ArrayRef.h"

#include <iostream>

@@ -103,35 +103,30 @@ fromRust(LLVMRustCounterExprKind Kind) {
}

extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
const char *const Filenames[],
size_t FilenamesLen,
const size_t *const Lengths,
size_t LengthsLen,
const char *const Filenames[], size_t FilenamesLen, // String start pointers
const size_t *const Lengths, size_t LengthsLen, // Corresponding lengths
RustStringRef BufferOut) {
if (FilenamesLen != LengthsLen) {
report_fatal_error(
"Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer");
}

SmallVector<std::string,32> FilenameRefs;
SmallVector<std::string, 32> FilenameRefs;
FilenameRefs.reserve(FilenamesLen);
for (size_t i = 0; i < FilenamesLen; i++) {
FilenameRefs.emplace_back(Filenames[i], Lengths[i]);
}
auto FilenamesWriter =
coverage::CoverageFilenamesSectionWriter(ArrayRef<std::string>(FilenameRefs));
auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
ArrayRef<std::string>(FilenameRefs));
auto OS = RawRustStringOstream(BufferOut);
FilenamesWriter.write(OS);
}

extern "C" void LLVMRustCoverageWriteMappingToBuffer(
const unsigned *VirtualFileMappingIDs,
unsigned NumVirtualFileMappingIDs,
const LLVMRustCounterExpression *RustExpressions,
unsigned NumExpressions,
const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs,
const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions,
const LLVMRustCounterMappingRegion *RustMappingRegions,
unsigned NumMappingRegions,
RustStringRef BufferOut) {
unsigned NumMappingRegions, RustStringRef BufferOut) {
// Convert from FFI representation to LLVM representation.
SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
MappingRegions.reserve(NumMappingRegions);
@@ -142,7 +137,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
coverage::CounterMappingRegion::MCDCParameters{},
#endif
Region.FileID, Region.ExpandedFileID,
Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
fromRust(Region.Kind));
}
@@ -158,29 +153,25 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(

auto CoverageMappingWriter = coverage::CoverageMappingWriter(
ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
Expressions,
MappingRegions);
Expressions, MappingRegions);
auto OS = RawRustStringOstream(BufferOut);
CoverageMappingWriter.write(OS);
}

extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(
LLVMValueRef F,
const char *FuncName,
size_t FuncNameLen) {
extern "C" LLVMValueRef
LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName,
size_t FuncNameLen) {
auto FuncNameRef = StringRef(FuncName, FuncNameLen);
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
}

extern "C" uint64_t LLVMRustCoverageHashByteArray(
const char *Bytes,
size_t NumBytes) {
extern "C" uint64_t LLVMRustCoverageHashByteArray(const char *Bytes,
size_t NumBytes) {
auto StrRef = StringRef(Bytes, NumBytes);
return IndexedInstrProf::ComputeHash(StrRef);
}

static void WriteSectionNameToString(LLVMModuleRef M,
InstrProfSectKind SK,
static void WriteSectionNameToString(LLVMModuleRef M, InstrProfSectKind SK,
RustStringRef Str) {
auto TargetTriple = Triple(unwrap(M)->getTargetTriple());
auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat());
@@ -193,8 +184,9 @@ extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M,
WriteSectionNameToString(M, IPSK_covmap, Str);
}

extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
extern "C" void
LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
WriteSectionNameToString(M, IPSK_covfun, Str);
}

2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -179,7 +179,7 @@ pub fn provide(providers: &mut Providers) {
.parenting
.get(&owner_id.def_id)
.copied()
.unwrap_or(ItemLocalId::from_u32(0)),
.unwrap_or(ItemLocalId::ZERO),
}
})
};
7 changes: 2 additions & 5 deletions compiler/rustc_middle/src/traits/solve/inspect.rs
Original file line number Diff line number Diff line change
@@ -121,8 +121,6 @@ pub enum ProbeStep<'tcx> {
/// used whenever there are multiple candidates to prove the
/// current goalby .
NestedProbe(Probe<'tcx>),
CommitIfOkStart,
CommitIfOkSuccess,
}

/// What kind of probe we're in. In case the probe represents a candidate, or
@@ -132,6 +130,8 @@ pub enum ProbeStep<'tcx> {
pub enum ProbeKind<'tcx> {
/// The root inference context while proving a goal.
Root { result: QueryResult<'tcx> },
/// Trying to normalize an alias by at least one stpe in `NormalizesTo`.
TryNormalizeNonRigid { result: QueryResult<'tcx> },
/// Probe entered when normalizing the self ty during candidate assembly
NormalizedSelfTyAssembly,
/// Some candidate to prove the current goal.
@@ -143,9 +143,6 @@ pub enum ProbeKind<'tcx> {
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly,
/// A call to `EvalCtxt::commit_if_ok` which failed, causing the work
/// to be discarded.
CommitIfOk,
/// During upcasting from some source object to target object type, used to
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
8 changes: 3 additions & 5 deletions compiler/rustc_middle/src/traits/solve/inspect/format.rs
Original file line number Diff line number Diff line change
@@ -100,6 +100,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
ProbeKind::Root { result } => {
write!(self.f, "ROOT RESULT: {result:?}")
}
ProbeKind::TryNormalizeNonRigid { result } => {
write!(self.f, "TRY NORMALIZE NON-RIGID: {result:?}")
}
ProbeKind::NormalizedSelfTyAssembly => {
write!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
}
@@ -109,9 +112,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
ProbeKind::UpcastProjectionCompatibility => {
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
}
ProbeKind::CommitIfOk => {
write!(self.f, "COMMIT_IF_OK:")
}
ProbeKind::MiscCandidate { name, result } => {
write!(self.f, "CANDIDATE {name}: {result:?}")
}
@@ -132,8 +132,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
}
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
ProbeStep::CommitIfOkSuccess => writeln!(this.f, "COMMIT_IF_OK SUCCESS")?,
}
}
Ok(())
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> {
let value = self.erase_regions(value);
debug!(?value);

if !value.has_projections() {
if !value.has_aliases() {
value
} else {
value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
@@ -81,7 +81,7 @@ impl<'tcx> TyCtxt<'tcx> {
let value = self.erase_regions(value);
debug!(?value);

if !value.has_projections() {
if !value.has_aliases() {
Ok(value)
} else {
let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
@@ -1077,7 +1077,7 @@ fn try_instance_mir<'tcx>(
let fields = def.all_fields();
for field in fields {
let field_ty = field.ty(tcx, args);
if field_ty.has_param() && field_ty.has_projections() {
if field_ty.has_param() && field_ty.has_aliases() {
return Err("cannot build drop shim for polymorphic type");
}
}
159 changes: 34 additions & 125 deletions compiler/rustc_trait_selection/src/solve/alias_relate.rs
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@
//! Doing this via a separate goal is called "deferred alias relation" and part
//! of our more general approach to "lazy normalization".
//!
//! This is done by first normalizing both sides of the goal, ending up in
//! either a concrete type, rigid alias, or an infer variable.
//! This is done by first structurally normalizing both sides of the goal, ending
//! up in either a concrete type, rigid alias, or an infer variable.
//! These are related further according to the rules below:
//!
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
@@ -14,18 +14,10 @@
//!
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally.
//!
//! Subtle: when relating an opaque to another type, we emit a
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
//! This nested goal starts out as ambiguous and does not actually define the opaque.
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
//! `NormalizesTo` goal, at which point the opaque is actually defined.
use super::EvalCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::GoalSource;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty;

impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
@@ -36,141 +28,58 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let tcx = self.tcx();
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;

let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
// Structurally normalize the lhs.
let lhs = if let Some(alias) = lhs.to_alias_ty(self.tcx()) {
let term = self.next_term_infer_of_kind(lhs);
self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
term
} else {
lhs
};

let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
// Structurally normalize the rhs.
let rhs = if let Some(alias) = rhs.to_alias_ty(self.tcx()) {
let term = self.next_term_infer_of_kind(rhs);
self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
term
} else {
rhs
};

// Apply the constraints.
self.try_evaluate_added_goals()?;
let lhs = self.resolve_vars_if_possible(lhs);
let rhs = self.resolve_vars_if_possible(rhs);
debug!(?lhs, ?rhs);

let variance = match direction {
ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
};

match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
(None, None) => {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}

(Some(alias), None) => {
self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)
self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
(None, Some(alias)) => {
self.relate_rigid_alias_non_alias(
param_env,
alias,
variance.xform(ty::Variance::Contravariant),
lhs,
)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
(None, Some(alias)) => self.relate_rigid_alias_non_alias(
param_env,
alias,
variance.xform(ty::Variance::Contravariant),
lhs,
),

(Some(alias_lhs), Some(alias_rhs)) => {
self.relate(param_env, alias_lhs, variance, alias_rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
}

/// Relate a rigid alias with another type. This is the same as
/// an ordinary relate except that we treat the outer most alias
/// constructor as rigid.
#[instrument(level = "debug", skip(self, param_env), ret)]
fn relate_rigid_alias_non_alias(
&mut self,
param_env: ty::ParamEnv<'tcx>,
alias: ty::AliasTy<'tcx>,
variance: ty::Variance,
term: ty::Term<'tcx>,
) -> QueryResult<'tcx> {
// NOTE: this check is purely an optimization, the structural eq would
// always fail if the term is not an inference variable.
if term.is_infer() {
let tcx = self.tcx();
// We need to relate `alias` to `term` treating only the outermost
// constructor as rigid, relating any contained generic arguments as
// normal. We do this by first structurally equating the `term`
// with the alias constructor instantiated with unconstrained infer vars,
// and then relate this with the whole `alias`.
//
// Alternatively we could modify `Equate` for this case by adding another
// variant to `StructurallyRelateAliases`.
let identity_args = self.fresh_args_for_item(alias.def_id);
let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
self.eq_structurally_relating_aliases(param_env, term, rigid_ctor.to_ty(tcx).into())?;
self.eq(param_env, alias, rigid_ctor)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
Err(NoSolution)
}
}

// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
/// Normalize the `term` to equate it later.
#[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_term(
&mut self,
param_env: ty::ParamEnv<'tcx>,
term: ty::Term<'tcx>,
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
match term.unpack() {
ty::TermKind::Ty(ty) => {
Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
}
ty::TermKind::Const(_) => {
if let Some(alias) = term.to_alias_ty(self.tcx()) {
let term = self.next_term_infer_of_kind(term);
self.add_normalizes_to_goal(Goal::new(
self.tcx(),
param_env,
ty::NormalizesTo { alias, term },
));
self.try_evaluate_added_goals()?;
Ok(Some(self.resolve_vars_if_possible(term)))
} else {
Ok(Some(term))
}
}
}
}

#[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_ty_recur(
&mut self,
param_env: ty::ParamEnv<'tcx>,
depth: usize,
ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> {
if !self.tcx().recursion_limit().value_within_limit(depth) {
return None;
}

let ty::Alias(kind, alias) = *ty.kind() else {
return Some(ty);
};

match self.commit_if_ok(|this| {
let tcx = this.tcx();
let normalized_ty = this.next_ty_infer();
let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() };
match kind {
ty::AliasKind::Opaque => {
// HACK: Unlike for associated types, `normalizes-to` for opaques
// is currently not treated as a function. We do not erase the
// expected term.
this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to));
}
ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => {
this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to))
}
}
this.try_evaluate_added_goals()?;
Ok(this.resolve_vars_if_possible(normalized_ty))
}) {
Ok(ty) => self.try_normalize_ty_recur(param_env, depth + 1, ty),
Err(NoSolution) => Some(ty),
}
}
}
13 changes: 10 additions & 3 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
@@ -312,11 +312,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec<Candidate<'tcx>> {
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
let certainty = Certainty::Maybe(cause);
let result = self.evaluate_added_goals_and_make_canonical_response(certainty).unwrap();
// This may fail if `try_evaluate_added_goals` overflows because it
// fails to reach a fixpoint but ends up getting an error after
// running for some additional step.
//
// FIXME: Add a test for this. It seems to be necessary for typenum but
// is incredibly hard to minimize as it may rely on being inside of a
// trait solver cycle.
let result = self.evaluate_added_goals_and_make_canonical_response(certainty);
let mut dummy_probe = self.inspect.new_probe();
dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result });
self.inspect.finish_probe(dummy_probe);
vec![Candidate { source, result }]
if let Ok(result) = result { vec![Candidate { source, result }] } else { vec![] }
}

#[instrument(level = "debug", skip_all)]
Original file line number Diff line number Diff line change
@@ -332,7 +332,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
/// whether an alias is rigid by using the trait solver. When instantiating a response
/// from the solver we assume that the solver correctly handled aliases and therefore
/// always relate them structurally here.
#[instrument(level = "debug", skip(infcx), ret)]
#[instrument(level = "debug", skip(infcx))]
fn unify_query_var_values(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
47 changes: 0 additions & 47 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs

This file was deleted.

79 changes: 59 additions & 20 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,6 @@ use rustc_middle::ty::{
use rustc_session::config::DumpSolverProofTree;
use rustc_span::DUMMY_SP;
use std::io::Write;
use std::iter;
use std::ops::ControlFlow;

use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
@@ -36,7 +35,6 @@ use super::{GoalSource, SolverMode};
pub use select::InferCtxtSelectExt;

mod canonical;
mod commit_if_ok;
mod probe;
mod select;

@@ -124,11 +122,6 @@ impl<'tcx> NestedGoals<'tcx> {
pub(super) fn is_empty(&self) -> bool {
self.normalizes_to_goals.is_empty() && self.goals.is_empty()
}

pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) {
self.normalizes_to_goals.extend(other.normalizes_to_goals);
self.goals.extend(other.goals)
}
}

#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
@@ -511,12 +504,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {

self.inspect.evaluate_added_goals_loop_start();

fn with_misc_source<'tcx>(
it: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
) -> impl Iterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)> {
iter::zip(iter::repeat(GoalSource::Misc), it)
}

// If this loop did not result in any progress, what's our final certainty.
let mut unchanged_certainty = Some(Certainty::Yes);
for goal in goals.normalizes_to_goals {
@@ -534,16 +521,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
unconstrained_goal,
)?;
// Add the nested goals from normalization to our own nested goals.
debug!(?nested_goals);
goals.goals.extend(nested_goals);

// Finally, equate the goal's RHS with the unconstrained var.
// We put the nested goals from this into goals instead of
// next_goals to avoid needing to process the loop one extra
// time if this goal returns something -- I don't think this
// matters in practice, though.
let eq_goals =
self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
goals.goals.extend(with_misc_source(eq_goals));
//
// SUBTLE:
// We structurally relate aliases here. This is necessary
// as we otherwise emit a nested `AliasRelate` goal in case the
// returned term is a rigid alias, resulting in overflow.
//
// It is correct as both `goal.predicate.term` and `unconstrained_rhs`
// start out as an unconstrained inference variable so any aliases get
// fully normalized when instantiating it.
//
// FIXME: Strictly speaking this may be incomplete if the normalized-to
// type contains an ambiguous alias referencing bound regions. We should
// consider changing this to only use "shallow structural equality".
self.eq_structurally_relating_aliases(
goal.param_env,
goal.predicate.term,
unconstrained_rhs,
)?;

// We only look at the `projection_ty` part here rather than
// looking at the "has changed" return from evaluate_goal,
@@ -731,6 +730,46 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
})
}

/// This should be used when relating a rigid alias with another type.
///
/// Normally we emit a nested `AliasRelate` when equating an inference
/// variable and an alias. This causes us to instead constrain the inference
/// variable to the alias without emitting a nested alias relate goals.
#[instrument(level = "debug", skip(self, param_env), ret)]
pub(super) fn relate_rigid_alias_non_alias(
&mut self,
param_env: ty::ParamEnv<'tcx>,
alias: ty::AliasTy<'tcx>,
variance: ty::Variance,
term: ty::Term<'tcx>,
) -> Result<(), NoSolution> {
// NOTE: this check is purely an optimization, the structural eq would
// always fail if the term is not an inference variable.
if term.is_infer() {
let tcx = self.tcx();
// We need to relate `alias` to `term` treating only the outermost
// constructor as rigid, relating any contained generic arguments as
// normal. We do this by first structurally equating the `term`
// with the alias constructor instantiated with unconstrained infer vars,
// and then relate this with the whole `alias`.
//
// Alternatively we could modify `Equate` for this case by adding another
// variant to `StructurallyRelateAliases`.
let identity_args = self.fresh_args_for_item(alias.def_id);
let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
let ctor_ty = rigid_ctor.to_ty(tcx);
let InferOk { value: (), obligations } = self
.infcx
.at(&ObligationCause::dummy(), param_env)
.trace(term, ctor_ty.into())
.eq_structurally_relating_aliases(term, ctor_ty.into())?;
debug_assert!(obligations.is_empty());
self.relate(param_env, alias, variance, rigid_ctor)
} else {
Err(NoSolution)
}
}

/// This sohuld only be used when we're either instantiating a previously
/// unconstrained "return value" or when we're sure that all aliases in
/// the types are rigid.
10 changes: 4 additions & 6 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
@@ -130,17 +130,14 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
self.candidates_recur(candidates, nested_goals, probe);
nested_goals.truncate(num_goals);
}
inspect::ProbeStep::EvaluateGoals(_)
| inspect::ProbeStep::CommitIfOkStart
| inspect::ProbeStep::CommitIfOkSuccess => (),
inspect::ProbeStep::EvaluateGoals(_) => (),
}
}

match probe.kind {
inspect::ProbeKind::NormalizedSelfTyAssembly
| inspect::ProbeKind::UnsizeAssembly
| inspect::ProbeKind::UpcastProjectionCompatibility
| inspect::ProbeKind::CommitIfOk => (),
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
// We add a candidate for the root evaluation if there
// is only one way to prove a given goal, e.g. for `WellFormed`.
//
@@ -157,7 +154,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
});
}
}
inspect::ProbeKind::MiscCandidate { name: _, result }
inspect::ProbeKind::TryNormalizeNonRigid { result }
| inspect::ProbeKind::MiscCandidate { name: _, result }
| inspect::ProbeKind::TraitCandidate { source: _, result } => {
candidates.push(InspectCandidate {
goal: self,
27 changes: 0 additions & 27 deletions compiler/rustc_trait_selection/src/solve/inspect/build.rs
Original file line number Diff line number Diff line change
@@ -220,8 +220,6 @@ enum WipProbeStep<'tcx> {
AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
NestedProbe(WipProbe<'tcx>),
CommitIfOkStart,
CommitIfOkSuccess,
}

impl<'tcx> WipProbeStep<'tcx> {
@@ -230,8 +228,6 @@ impl<'tcx> WipProbeStep<'tcx> {
WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart,
WipProbeStep::CommitIfOkSuccess => inspect::ProbeStep::CommitIfOkSuccess,
}
}
}
@@ -467,29 +463,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}

/// Used by `EvalCtxt::commit_if_ok` to flatten the work done inside
/// of the probe into the parent.
pub fn integrate_snapshot(&mut self, probe: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
match (this, *probe.state.unwrap()) {
(
DebugSolver::Probe(WipProbe { steps, .. })
| DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
evaluation: WipProbe { steps, .. },
..
}),
DebugSolver::Probe(probe),
) => {
steps.push(WipProbeStep::CommitIfOkStart);
assert_eq!(probe.kind, None);
steps.extend(probe.steps);
steps.push(WipProbeStep::CommitIfOkSuccess);
}
_ => unreachable!(),
}
}
}

pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None })
}
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
@@ -177,7 +177,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
let infcx = self.at.infcx;
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
if !ty.has_projections() {
if !ty.has_aliases() {
return Ok(ty);
}

@@ -204,7 +204,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
let infcx = self.at.infcx;
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
if !ct.has_projections() {
if !ct.has_aliases() {
return Ok(ct);
}

65 changes: 40 additions & 25 deletions compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::inspect::ProbeKind;
use rustc_infer::traits::specialization_graph::LeafDef;
use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::{
@@ -30,14 +31,41 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let def_id = goal.predicate.def_id();
let def_kind = self.tcx().def_kind(def_id);
match def_kind {
DefKind::OpaqueTy => return self.normalize_opaque_type(goal),
_ => self.set_is_normalizes_to_goal(),
self.set_is_normalizes_to_goal();
debug_assert!(self.term_is_fully_unconstrained(goal));
let normalize_result = self
.probe(|&result| ProbeKind::TryNormalizeNonRigid { result })
.enter(|this| this.normalize_at_least_one_step(goal));

match normalize_result {
Ok(res) => Ok(res),
Err(NoSolution) => {
let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal;
if alias.opt_kind(self.tcx()).is_some() {
self.relate_rigid_alias_non_alias(
param_env,
alias,
ty::Variance::Invariant,
term,
)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
// FIXME(generic_const_exprs): we currently do not support rigid
// unevaluated constants.
Err(NoSolution)
}
}
}
}

debug_assert!(self.term_is_fully_unconstrained(goal));
/// Normalize the given alias by at least one step. If the alias is rigid, this
/// returns `NoSolution`.
#[instrument(level = "debug", skip(self), ret)]
fn normalize_at_least_one_step(
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let def_id = goal.predicate.def_id();
match self.tcx().def_kind(def_id) {
DefKind::AssocTy | DefKind::AssocConst => {
match self.tcx().associated_item(def_id).container {
@@ -52,35 +80,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
DefKind::AnonConst => self.normalize_anon_const(goal),
DefKind::TyAlias => self.normalize_weak_type(goal),
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)),
}
}

/// When normalizing an associated item, constrain the result to `term`.
///
/// While `NormalizesTo` goals have the normalized-to term as an argument,
/// this argument is always fully unconstrained for associated items.
/// It is therefore appropriate to instead think of these `NormalizesTo` goals
/// as function returning a term after normalizing.
///
/// When equating an inference variable and an alias, we tend to emit `alias-relate`
/// goals and only actually instantiate the inference variable with an alias if the
/// alias is rigid. However, this means that constraining the expected term of
/// such goals ends up fully structurally normalizing the resulting type instead of
/// only by one step. To avoid this we instead use structural equality here, resulting
/// in each `NormalizesTo` only projects by a single step.
/// When normalizing an associated item, constrain the expected term to `term`.
///
/// Not doing so, currently causes issues because trying to normalize an opaque type
/// during alias-relate doesn't actually constrain the opaque if the concrete type
/// is an inference variable. This means that `NormalizesTo` for associated types
/// normalizing to an opaque type always resulted in ambiguity, breaking tests e.g.
/// tests/ui/type-alias-impl-trait/issue-78450.rs.
/// We know `term` to always be a fully unconstrained inference variable, so
/// `eq` should never fail here. However, in case `term` contains aliases, we
/// emit nested `AliasRelate` goals to structurally normalize the alias.
pub fn instantiate_normalizes_to_term(
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
term: ty::Term<'tcx>,
) {
self.eq_structurally_relating_aliases(goal.param_env, goal.predicate.term, term)
self.eq(goal.param_env, goal.predicate.term, term)
.expect("expected goal term to be fully unconstrained");
}
}
Original file line number Diff line number Diff line change
@@ -58,12 +58,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}

let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
if expected.is_ty_var() {
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
}

// Otherwise, define a new opaque type
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
self.add_item_bounds_for_hidden_type(
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -311,7 +311,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {

let infcx = self.selcx.infcx;

if obligation.predicate.has_projections() {
if obligation.predicate.has_aliases() {
let mut obligations = Vec::new();
let predicate = normalize_with_depth_to(
&mut self.selcx,
2 changes: 2 additions & 0 deletions compiler/rustc_trait_selection/src/traits/normalize.rs
Original file line number Diff line number Diff line change
@@ -101,6 +101,8 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
value: &T,
reveal: Reveal,
) -> bool {
// This mirrors `ty::TypeFlags::HAS_ALIASES` except that we take `Reveal` into account.

let mut flags = ty::TypeFlags::HAS_TY_PROJECTION
| ty::TypeFlags::HAS_TY_WEAK
| ty::TypeFlags::HAS_TY_INHERENT
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -431,7 +431,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>(

let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);

let mut result = if projected_term.has_projections() {
let mut result = if projected_term.has_aliases() {
let normalized_ty = normalize_with_depth_to(
selcx,
param_env,
@@ -595,7 +595,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args);

let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
if ty.has_projections() {
if ty.has_aliases() {
ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
}

Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ where
type QueryResponse = T;

fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
if !key.value.value.has_projections() { Some(key.value.value) } else { None }
if !key.value.value.has_aliases() { Some(key.value.value) } else { None }
}

fn perform_query(
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
@@ -1060,7 +1060,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// so we will try to normalize the obligation and evaluate again.
// we will replace it with new solver in the future.
if EvaluationResult::EvaluatedToErr == result
&& fresh_trait_pred.has_projections()
&& fresh_trait_pred.has_aliases()
&& fresh_trait_pred.is_global()
{
let mut nested_obligations = Vec::new();
4 changes: 2 additions & 2 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
@@ -241,9 +241,9 @@ fn layout_of_uncached<'tcx>(

// Arrays and slices.
ty::Array(element, mut count) => {
if count.has_projections() {
if count.has_aliases() {
count = tcx.normalize_erasing_regions(param_env, count);
if count.has_projections() {
if count.has_aliases() {
return Err(error(cx, LayoutError::Unknown(ty)));
}
}
6 changes: 4 additions & 2 deletions compiler/rustc_type_ir/src/flags.rs
Original file line number Diff line number Diff line change
@@ -78,8 +78,10 @@ bitflags! {
/// Does this have `ConstKind::Unevaluated`?
const HAS_CT_PROJECTION = 1 << 14;

/// Could this type be normalized further?
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits()
/// Does this have `Alias` or `ConstKind::Unevaluated`?
///
/// Rephrased, could this term be normalized further?
const HAS_ALIASES = TypeFlags::HAS_TY_PROJECTION.bits()
| TypeFlags::HAS_TY_WEAK.bits()
| TypeFlags::HAS_TY_OPAQUE.bits()
| TypeFlags::HAS_TY_INHERENT.bits()
4 changes: 2 additions & 2 deletions compiler/rustc_type_ir/src/visit.rs
Original file line number Diff line number Diff line change
@@ -223,8 +223,8 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
self.has_vars_bound_at_or_above(ty::INNERMOST)
}

fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
fn has_aliases(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ALIASES)
}

fn has_inherent_projections(&self) -> bool {
3 changes: 2 additions & 1 deletion library/core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::Freeze;

/// Provides the pointer metadata type of any pointed-to type.
///
@@ -57,7 +58,7 @@ pub trait Pointee {
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
// in `library/core/src/ptr/metadata.rs`
// in sync with those here:
type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin;
type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze;
}

/// Pointers to types implementing this trait alias are “thin”.
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
#![feature(duration_constructors)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(freeze)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(float_minimum_maximum)]
3 changes: 2 additions & 1 deletion library/core/tests/ptr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::cell::RefCell;
use core::marker::Freeze;
use core::mem::{self, MaybeUninit};
use core::num::NonZero;
use core::ptr;
@@ -841,7 +842,7 @@ fn ptr_metadata_bounds() {
fn static_assert_expected_bounds_for_metadata<Meta>()
where
// Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin + Freeze,
{
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.17.0
0.17.1
11 changes: 10 additions & 1 deletion src/doc/rustdoc/src/what-is-rustdoc.md
Original file line number Diff line number Diff line change
@@ -34,6 +34,9 @@ the main page is located in `doc/lib/index.html`. If you open that up in
a web browser, you will see a page with a search bar, and "Crate lib" at the
top, with no contents.

You can also use `cargo doc` to generate documentation for the whole project.
See [Using rustdoc with Cargo](#using-rustdoc-with-cargo).

## Configuring rustdoc

There are two problems with this: first, why does it
@@ -79,7 +82,13 @@ docs. Instead of the `rustdoc` command, we could have done this:
$ cargo doc
```

Internally, this calls out to `rustdoc` like this:
If you want `cargo` to automatically open the generated documentation, you can use:

```bash
$ cargo doc --open
```

Internally, `cargo doc` calls out to `rustdoc` like this:

```bash
$ rustdoc --crate-name docs src/lib.rs -o <path>/docs/target/doc -L
4 changes: 2 additions & 2 deletions src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ nav.sub {
in rustdoc.css */

/* Begin theme: light */
:root {
:root, :root:not([data-theme]) {
--main-background-color: white;
--main-color: black;
--settings-input-color: #2196f3;
@@ -140,7 +140,7 @@ nav.sub {

@media (prefers-color-scheme: dark) {
/* Begin theme: dark */
:root {
:root, :root:not([data-theme]) {
--main-background-color: #353535;
--main-color: #ddd;
--settings-input-color: #2196f3;
8 changes: 7 additions & 1 deletion src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
@@ -2315,8 +2315,14 @@ in src-script.js and main.js
tooling to ensure different themes all define all the variables. Do not
alter their formatting. */

/*
About `:root:not([data-theme])`: if for any reason the JS is enabled but cannot be loaded,
`noscript` won't be enabled and the doc will have no color applied. To do around this, we
add a selector check that if `data-theme` is not defined, then we apply the light theme
by default.
*/
/* Begin theme: light */
:root[data-theme="light"] {
:root[data-theme="light"], :root:not([data-theme]) {
--main-background-color: white;
--main-color: black;
--settings-input-color: #2196f3;
7 changes: 5 additions & 2 deletions src/tools/tidy/src/rustdoc_css_themes.rs
Original file line number Diff line number Diff line change
@@ -74,8 +74,11 @@ fn compare_themes<'a>(
(noscript_css_line_number, noscript_css_line),
) in rustdoc_css_lines.zip(noscript_css_lines)
{
if noscript_css_line.starts_with(":root {")
&& rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
if noscript_css_line.starts_with(":root, :root:not([data-theme]) {")
&& (rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
|| rustdoc_css_line.starts_with(&format!(
r#":root[data-theme="{name}"], :root:not([data-theme]) {{"#
)))
{
// selectors are different between rustdoc.css and noscript.css
// that's why they both exist: one uses JS, the other uses media queries
14 changes: 14 additions & 0 deletions tests/rustdoc-gui/javascript-disabled.goml
Original file line number Diff line number Diff line change
@@ -3,4 +3,18 @@
javascript: false

go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
show-text: true
assert-css: (".sub", {"display": "none"})

// Even though JS is disabled, we should still have themes applied. Links are never black-colored
// if styles are applied so we check that they are not.
assert-css-false: ("a.src", {"color": "#000"})

javascript: true
fail-on-request-error: false
block-network-request: "*.js"
reload:

// JS is enabled but wasn't loaded, we should still have the light theme applied. Links are never
// black-colored if styles are applied so we check that they are not.
assert-css-false: ("a.src", {"color": "#000"})
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ LL | cmp_eq
|
= note: cannot satisfy `_: Scalar`
note: required by a bound in `cmp_eq`
--> $DIR/ambig-hr-projection-issue-93340.rs:9:22
--> $DIR/ambig-hr-projection-issue-93340.rs:10:22
|
LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
| ^^^^^^ required by this bound in `cmp_eq`
@@ -15,34 +15,6 @@ help: consider specifying the generic arguments
LL | cmp_eq::<A, B, O>
| +++++++++++

error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
--> $DIR/ambig-hr-projection-issue-93340.rs:16:5
|
LL | cmp_eq
| ^^^^^^

error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
--> $DIR/ambig-hr-projection-issue-93340.rs:16:5
|
LL | cmp_eq
| ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0275]: overflow evaluating the requirement `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> _ {cmp_eq::<O, ..., ...>} <: ...`
--> $DIR/ambig-hr-projection-issue-93340.rs:14:51
|
LL | ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
| ___________________________________________________^
LL | |
LL | | cmp_eq
LL | |
LL | |
LL | |
LL | | }
| |_^

error: aborting due to 4 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0275, E0283.
For more information about an error, try `rustc --explain E0275`.
For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ LL | cmp_eq
|
= note: cannot satisfy `_: Scalar`
note: required by a bound in `cmp_eq`
--> $DIR/ambig-hr-projection-issue-93340.rs:9:22
--> $DIR/ambig-hr-projection-issue-93340.rs:10:22
|
LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
| ^^^^^^ required by this bound in `cmp_eq`
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ revisions: old next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
pub trait Scalar: 'static {
type RefType<'a>: ScalarRef<'a>;
@@ -12,11 +13,8 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT

fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
//[next]~^ ERROR overflow evaluating the requirement
cmp_eq
//~^ ERROR type annotations needed
//[next]~| ERROR overflow evaluating the requirement
//[next]~| ERROR overflow evaluating the requirement
}

fn main() {}
28 changes: 22 additions & 6 deletions tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:12:23
--> $DIR/recursive-coroutine-boxed.rs:14:23
|
LL | let mut gen = Box::pin(foo());
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
@@ -12,12 +12,28 @@ help: consider specifying the generic argument
LL | let mut gen = Box::<T>::pin(foo());
| +++++

error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:9:13
error[E0308]: mismatched types
--> $DIR/recursive-coroutine-boxed.rs:13:5
|
LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
| ---------------------------------------
| |
| the expected opaque type
| expected `impl Coroutine<Yield = (), Return = ()>` because of return type
...
LL | / || {
LL | | let mut gen = Box::pin(foo());
LL | |
LL | | let mut r = gen.as_mut().resume(());
... |
LL | | }
LL | | }
| |_____^ types differ
|
LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
= note: expected opaque type `impl Coroutine<Yield = (), Return = ()>`
found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:13:5: 13:7}`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0282`.
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
6 changes: 4 additions & 2 deletions tests/ui/impl-trait/recursive-coroutine-boxed.rs
Original file line number Diff line number Diff line change
@@ -7,8 +7,10 @@
use std::ops::{Coroutine, CoroutineState};

fn foo() -> impl Coroutine<Yield = (), Return = ()> {
//[next]~^ ERROR type annotations needed
|| {
// FIXME(-Znext-solver): this fails with a mismatched types as the
// hidden type of the opaque ends up as {type error}. We should not
// emit errors for such goals.
|| { //[next]~ ERROR mismatched types
let mut gen = Box::pin(foo());
//[next]~^ ERROR type annotations needed
let mut r = gen.as_mut().resume(());
11 changes: 11 additions & 0 deletions tests/ui/sanitizer/cfi-closures.rs
Original file line number Diff line number Diff line change
@@ -77,3 +77,14 @@ fn closure_addr_taken() {
let call = Fn::<()>::call;
use_closure(call, &f);
}

fn use_closure_once<C>(call: extern "rust-call" fn(C, ()) -> i32, f: C) -> i32 {
call(f, ())
}

#[test]
fn closure_once_addr_taken() {
let g = || 3;
let call2 = FnOnce::<()>::call_once;
use_closure_once(call2, g);
}