Skip to content
Closed
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions compiler/rustc_ast/src/util/parser.rs
Original file line number Diff line number Diff line change
@@ -212,7 +212,8 @@ impl AssocOp {
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
pub fn can_continue_expr_unambiguously(&self) -> bool {
use AssocOp::*;
match self {
matches!(
self,
BitXor | // `{ 42 } ^ 3`
Assign | // `{ 42 } = { 42 }`
Divide | // `{ 42 } / 42`
@@ -225,9 +226,8 @@ impl AssocOp {
As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
Colon => true, // `{ 42 }: usize`
_ => false,
}
Colon, // `{ 42 }: usize`
)
}
}

5 changes: 1 addition & 4 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
@@ -53,10 +53,7 @@ pub(crate) enum LaterUseKind {

impl BorrowExplanation {
pub(crate) fn is_explained(&self) -> bool {
match self {
BorrowExplanation::Unexplained => false,
_ => true,
}
!matches!(self, BorrowExplanation::Unexplained)
}
pub(crate) fn add_explanation_to_diagnostic<'tcx>(
&self,
14 changes: 7 additions & 7 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -2110,14 +2110,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
_ => constraint_sup_scc != target_scc,
}
} else {
match categorized_path[*i].category {
!matches!(
categorized_path[*i].category,
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal
| ConstraintCategory::Predicate(_) => false,
_ => true,
}
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal
| ConstraintCategory::Predicate(_)
)
}
};

10 changes: 2 additions & 8 deletions compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
@@ -138,17 +138,11 @@ impl<'tcx> DefiningTy<'tcx> {
}

pub fn is_fn_def(&self) -> bool {
match *self {
DefiningTy::FnDef(..) => true,
_ => false,
}
matches!(*self, DefiningTy::FnDef(..))
}

pub fn is_const(&self) -> bool {
match *self {
DefiningTy::Const(..) => true,
_ => false,
}
matches!(*self, DefiningTy::Const(..))
}

pub fn def_id(&self) -> DefId {
5 changes: 1 addition & 4 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
@@ -124,10 +124,7 @@ fn push_debuginfo_type_name<'tcx>(
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
// types out to aid debugging in MSVC.
let is_slice_or_str = match *inner_type.kind() {
ty::Slice(_) | ty::Str => true,
_ => false,
};
let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);

if !cpp_like_names {
output.push('&');
5 changes: 1 addition & 4 deletions compiler/rustc_const_eval/src/const_eval/error.rs
Original file line number Diff line number Diff line change
@@ -25,10 +25,7 @@ pub enum ConstEvalErrKind {

impl MachineStopType for ConstEvalErrKind {
fn is_hard_err(&self) -> bool {
match self {
Self::Panic { .. } => true,
_ => false,
}
matches!(self, Self::Panic { .. })
}
}

4 changes: 1 addition & 3 deletions compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
@@ -51,10 +51,8 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// If the function itself is not annotated with `const`, it may still be a `const fn`
// if it resides in a const trait impl.
is_parent_const_impl_raw(tcx, hir_id)
} else if let hir::Node::Ctor(_) = node {
true
} else {
false
matches!(node, hir::Node::Ctor(_))
}
}

Original file line number Diff line number Diff line change
@@ -138,10 +138,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
args: &[GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
let args = args.iter().cloned().filter(|arg| match arg.unpack() {
GenericArgKind::Lifetime(_) => false,
_ => true,
});
let args =
args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
if args.clone().next().is_some() {
self.generic_delimiters(|cx| cx.comma_sep(args))
} else {
6 changes: 2 additions & 4 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
@@ -345,10 +345,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

// Figure out how to pass which arguments.
// The Rust ABI is special: ZST get skipped.
let rust_abi = match caller_abi {
Abi::Rust | Abi::RustCall => true,
_ => false,
};
let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall);

// We have two iterators: Where the arguments come from,
// and where they go to.

Original file line number Diff line number Diff line change
@@ -131,10 +131,7 @@ impl Qualifs<'mir, 'tcx> {
.body
.basic_blocks()
.iter_enumerated()
.find(|(_, block)| match block.terminator().kind {
TerminatorKind::Return => true,
_ => false,
})
.find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
.map(|(bb, _)| bb);

let return_block = match return_block {
11 changes: 6 additions & 5 deletions compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
@@ -170,11 +170,12 @@ impl Qualif for NeedsNonConstDrop {
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation)
});
match implsrc {
Ok(Some(ImplSource::ConstDrop(_)))
| Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
_ => true,
}
!matches!(
implsrc,
Ok(Some(
ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
))
)
}

fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
9 changes: 4 additions & 5 deletions compiler/rustc_lexer/src/unescape.rs
Original file line number Diff line number Diff line change
@@ -68,11 +68,10 @@ pub enum EscapeError {
impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
match self {
EscapeError::UnskippedWhitespaceWarning => false,
EscapeError::MultipleSkippedLinesWarning => false,
_ => true,
}
!matches!(
self,
EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
)
}
}

10 changes: 5 additions & 5 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
@@ -538,12 +538,12 @@ impl InterpError<'_> {
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
/// so this method lets us detect them and `bug!` on unexpected errors.
pub fn formatted_string(&self) -> bool {
match self {
matches!(
self,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
_ => false,
}
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
)
}

/// Should this error be reported as a hard error, preventing compilation, or a soft error,
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
@@ -485,7 +485,7 @@ fn inject_statement(

// Non-code expressions are injected into the coverage map, without generating executable code.
fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false });
debug_assert!(matches!(expression, CoverageKind::Expression { .. }));
debug!(" injecting non-code expression {:?}", expression);
let inject_in_bb = mir::START_BLOCK;
let data = &mut mir_body[inject_in_bb];
7 changes: 3 additions & 4 deletions compiler/rustc_mir_transform/src/coverage/spans.rs
Original file line number Diff line number Diff line change
@@ -94,10 +94,9 @@ impl CoverageSpan {
stmt_index: usize,
) -> Self {
let is_closure = match statement.kind {
StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
_ => false,
},
StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _))
}
_ => false,
};

2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/reveal_all.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// This pass must run before inlining, since we insert callee bodies in RevealAll mode.
// Do not apply this transformation to generators.
if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx))
if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
&& body.generator.is_none()
{
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
5 changes: 2 additions & 3 deletions compiler/rustc_mir_transform/src/unreachable_prop.rs
Original file line number Diff line number Diff line change
@@ -27,9 +27,8 @@ impl MirPass<'_> for UnreachablePropagation {
// This is a temporary solution that handles possibly diverging asm statements.
// Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
let asm_stmt_in_block = || {
bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind {
StatementKind::LlvmInlineAsm(..) => true,
_ => false,
bb_data.statements.iter().any(|stmt: &Statement<'_>| {
matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
})
};

5 changes: 1 addition & 4 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
@@ -320,10 +320,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
match pred.constness {
ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
_ => false,
}
matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
}

/// Returns `true` if the predicate is considered `const` to
7 changes: 2 additions & 5 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
@@ -436,11 +436,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
// Can/should be extended in the future.
let needs_parens = !has_parens
&& match self.expr.kind {
hir::ExprKind::Cast(..) => true,
_ => false,
};
let needs_parens =
!has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));

let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
if needs_parens {
18 changes: 18 additions & 0 deletions compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr);
self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
@@ -167,6 +168,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn suggest_box_deref(
&self,
err: &mut DiagnosticBuilder<'_>,
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) {
if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
"try dereferencing the `Box`",
"*".to_string(),
Applicability::MachineApplicable,
);
}
}

/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(
9 changes: 6 additions & 3 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
@@ -1698,15 +1698,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, index);
let adjustments = self.adjust_steps(&autoderef);
if field.vis.is_accessible_from(def_scope, self.tcx) {
let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());

self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
return field_ty;
}
private_candidate = Some((base_def.did, field_ty));
private_candidate = Some((adjustments, base_def.did, field_ty));
}
}
ty::Tuple(tys) => {
@@ -1729,7 +1729,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));

if let Some((did, field_ty)) = private_candidate {
if let Some((adjustments, did, field_ty)) = private_candidate {
// (#90483) apply adjustments to avoid ExprUseVisitor from
// creating erroneous projection.
self.apply_adjustments(base, adjustments);
self.ban_private_field_access(expr, expr_t, field, did);
return field_ty;
}
Original file line number Diff line number Diff line change
@@ -300,7 +300,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(_, id), .. },
)) if *id == def_id => true,
)) => *id == def_id,
_ => false,
})
})
7 changes: 1 addition & 6 deletions library/std/src/net/ip.rs
Original file line number Diff line number Diff line change
@@ -878,12 +878,7 @@ impl Ipv4Addr {
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
match self.octets() {
[192, 0, 2, _] => true,
[198, 51, 100, _] => true,
[203, 0, 113, _] => true,
_ => false,
}
matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
}

/// Converts this address to an [IPv4-compatible] [`IPv6` address].
2 changes: 1 addition & 1 deletion library/std/src/os/unix/net/addr.rs
Original file line number Diff line number Diff line change
@@ -159,7 +159,7 @@ impl SocketAddr {
#[must_use]
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn is_unnamed(&self) -> bool {
if let AddressKind::Unnamed = self.address() { true } else { false }
matches!(self.address(), AddressKind::Unnamed)
}

/// Returns the contents of this address if it is a `pathname` address.
1 change: 1 addition & 0 deletions src/doc/rustdoc/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The Rustdoc Book

- [What is rustdoc?](what-is-rustdoc.md)
- [How to read rustdoc output](how-to-read-rustdoc.md)
- [How to write documentation](how-to-write-documentation.md)
- [What to include (and exclude)](what-to-include.md)
- [Command-line arguments](command-line-arguments.md)
107 changes: 107 additions & 0 deletions src/doc/rustdoc/src/how-to-read-rustdoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# How to read rustdoc output

Rustdoc's HTML output includes a friendly and useful navigation interface which
makes it easier for users to navigate and understand your code.
This chapter covers the major features of that interface,
and is a great starting point for documentation authors and users alike.

## Structure

The `rustdoc` output is divided into three sections.
Along the left side of each page is a quick navigation bar,
which shows contextual information about the current entry.
The rest of the page is taken up by the search interface at the top
and the documentation for the current item below that.

## The Item Documentation

The majority of the screen is taken up with the documentation text for the item
currently being viewed.
At the top is some at-a-glance info and controls:

- the type and name of the item,
such as "Struct `std::time::Duration`",
- a button to copy the item's path to the clipboard,
which is a clipboard item
- a button to collapse or expand the top-level documentation for that item
(`[+]` or `[-]`),
- a link to the source code (`[src]`),
if [configured](the-doc-attribute.html#html_no_source),
and present (the source may not be available if
the documentation was created with `cargo doc --no-deps`),
- and the version in which the item became stable,
if it's a stable item in the standard library.

Below this is the main documentation for the item,
including a definition or function signature if appropriate,
followed by a list of fields or variants for Rust types.
Finally, the page lists associated functions and trait implementations,
including automatic and blanket implementations that `rustdoc` knows about.

### Navigation

Subheadings, variants, fields, and many other things in this documentation
are anchors and can be clicked on and deep-linked to,
which is a great way to communicate exactly what you're talking about.
The typograpical character "§" appears next to lines with anchors on them
when hovered or given keyboard focus.

## The Navigation Bar

For example, when looking at documentation for the crate root,
it shows all the crates documented in the documentation bundle,
and quick links to the modules, structs, traits, functions, and macros available
from the current crate.
At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
alongside the current crate's name and version,
or the current item whose documentation is being displayed.

## The Theme Picker and Search Interface

When viewing `rustdoc`'s output in a browser with JavaScript enabled,
a dynamic interface appears at the top of the page.
To the left is the theme picker, denoted with a paint-brush icon,
and the search interface, help screen, and options appear to the right of that.

### The Theme Picker

Clicking on the theme picker provides a list of themes -
by default `ayu`, `light`, and `dark` -
which are available for viewing.

### The Search Interface

Typing in the search bar instantly searches the available documentation for
the string entered with a fuzzy matching algorithm that is tolerant of minor
typos.

By default, the search results give are "In Names",
meaning that the fuzzy match is made against the names of items.
Matching names are shown on the left, and the first few words of their
descriptions are given on the right.
By clicking an item, you will navigate to its particular documentation.

There are two other sets of results, shown as tabs in the search results pane.
"In Parameters" shows matches for the string in the types of parameters to
functions, and "In Return Types" shows matches in the return types of functions.
Both are very useful when looking for a function whose name you can't quite
bring to mind when you know the type you have or want.

When typing in the search bar, you can prefix your search term with a type
followed by a colon (such as `mod:`) to restrict the results to just that
kind of item. (The available items are listed in the help popup.)

### Shortcuts

Pressing `S` while focused elsewhere on the page will move focus to the
search bar, and pressing `?` shows the help screen,
which includes all these shortcuts and more.
Pressing `T` focuses the theme picker.

When the search results are focused,
the left and right arrows move between tabs and the up and down arrows move
among the results.
Pressing the enter or return key opens the highlighted result.

When looking at the documentation for an item, the plus and minus keys expand
and collapse all sections in the document.
4 changes: 3 additions & 1 deletion src/test/mir-opt/issue-78192.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// EMIT_MIR issue_78192.f.InstCombine.diff
// compile-flags: -Zmir-opt-level=1 -Zinline-mir
pub fn f<T>(a: &T) -> *const T {
let b: &*const T = &(a as *const T);
*b
@@ -7,3 +7,5 @@ pub fn f<T>(a: &T) -> *const T {
fn main() {
f(&2);
}

// EMIT_MIR issue_78192.f.InstCombine.diff
16 changes: 16 additions & 0 deletions src/test/ui/suggestions/boxed-variant-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
enum Ty {
Unit,
List(Box<Ty>),
}

fn foo(x: Ty) -> Ty {
match x {
Ty::Unit => Ty::Unit,
Ty::List(elem) => foo(elem),
//~^ ERROR mismatched types
//~| HELP try dereferencing the `Box`
//~| HELP try using a variant of the expected enum
}
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/boxed-variant-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0308]: mismatched types
--> $DIR/boxed-variant-field.rs:9:31
|
LL | Ty::List(elem) => foo(elem),
| ^^^^ expected enum `Ty`, found struct `Box`
|
= note: expected enum `Ty`
found struct `Box<Ty>`
help: try dereferencing the `Box`
|
LL | Ty::List(elem) => foo(*elem),
| +
help: try using a variant of the expected enum
|
LL | Ty::List(elem) => foo(Ty::List(elem)),
| ~~~~~~~~~~~~~~

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
4 changes: 4 additions & 0 deletions src/test/ui/terr-sorts.stderr
Original file line number Diff line number Diff line change
@@ -6,6 +6,10 @@ LL | want_foo(b);
|
= note: expected struct `Foo`
found struct `Box<Foo>`
help: try dereferencing the `Box`
|
LL | want_foo(*b);
| +

error: aborting due to previous error

14 changes: 14 additions & 0 deletions src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// edition:2021

mod m {
pub struct S { foo: i32 }
impl S {
pub fn foo(&self) -> i32 { 42 }
}
}

fn bar(s: &m::S) {
|| s.foo() + s.foo; //~ ERROR E0616
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0616]: field `foo` of struct `S` is private
--> $DIR/issue-90483-inaccessible-field-adjustment.rs:11:18
|
LL | || s.foo() + s.foo;
| ^^^ private field
|
help: a method `foo` also exists, call it with parentheses
|
LL | || s.foo() + s.foo();
| ++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0616`.