1pub mod ambiguity;
2pub mod call_kind;
3pub mod fulfillment_errors;
4pub mod on_unimplemented;
5pub mod on_unimplemented_condition;
6pub mod on_unimplemented_format;
7mod overflow;
8pub mod suggestions;
9
10use std::{fmt, iter};
11
12use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
13use rustc_data_structures::unord::UnordSet;
14use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
15use rustc_hir::def_id::{DefId, LocalDefId};
16use rustc_hir::intravisit::Visitor;
17use rustc_hir::{self as hir, AmbigArg};
18use rustc_infer::traits::solve::Goal;
19use rustc_infer::traits::{
20 DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
21 PredicateObligation, SelectionError,
22};
23use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
24use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
25use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span, Symbol};
26use tracing::{info, instrument};
27
28pub use self::overflow::*;
29use crate::error_reporting::TypeErrCtxt;
30use crate::traits::{FulfillmentError, FulfillmentErrorCode};
31
32#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
37pub enum CandidateSimilarity {
38 Exact { ignoring_lifetimes: bool },
39 Fuzzy { ignoring_lifetimes: bool },
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct ImplCandidate<'tcx> {
44 pub trait_ref: ty::TraitRef<'tcx>,
45 pub similarity: CandidateSimilarity,
46 impl_def_id: DefId,
47}
48
49enum GetSafeTransmuteErrorAndReason {
50 Silent,
51 Default,
52 Error { err_msg: String, safe_transmute_explanation: Option<String> },
53}
54
55pub struct FindExprBySpan<'hir> {
57 pub span: Span,
58 pub result: Option<&'hir hir::Expr<'hir>>,
59 pub ty_result: Option<&'hir hir::Ty<'hir>>,
60 pub include_closures: bool,
61 pub tcx: TyCtxt<'hir>,
62}
63
64impl<'hir> FindExprBySpan<'hir> {
65 pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
66 Self { span, result: None, ty_result: None, tcx, include_closures: false }
67 }
68}
69
70impl<'v> Visitor<'v> for FindExprBySpan<'v> {
71 type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
72
73 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
74 self.tcx
75 }
76
77 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
78 if self.span == ex.span {
79 self.result = Some(ex);
80 } else {
81 if let hir::ExprKind::Closure(..) = ex.kind
82 && self.include_closures
83 && let closure_header_sp = self.span.with_hi(ex.span.hi())
84 && closure_header_sp == ex.span
85 {
86 self.result = Some(ex);
87 }
88 hir::intravisit::walk_expr(self, ex);
89 }
90 }
91
92 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
93 if self.span == ty.span {
94 self.ty_result = Some(ty.as_unambig_ty());
95 } else {
96 hir::intravisit::walk_ty(self, ty);
97 }
98 }
99}
100
101#[derive(Clone)]
103pub enum ArgKind {
104 Arg(String, String),
106
107 Tuple(Option<Span>, Vec<(String, String)>),
112}
113
114impl ArgKind {
115 fn empty() -> ArgKind {
116 ArgKind::Arg("_".to_owned(), "_".to_owned())
117 }
118
119 pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
122 match t.kind() {
123 ty::Tuple(tys) => ArgKind::Tuple(
124 span,
125 tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
126 ),
127 _ => ArgKind::Arg("_".to_owned(), t.to_string()),
128 }
129 }
130}
131
132#[derive(Copy, Clone)]
133pub enum DefIdOrName {
134 DefId(DefId),
135 Name(&'static str),
136}
137
138impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
139 pub fn report_fulfillment_errors(
140 &self,
141 mut errors: Vec<FulfillmentError<'tcx>>,
142 ) -> ErrorGuaranteed {
143 #[derive(Debug)]
144 struct ErrorDescriptor<'tcx> {
145 goal: Goal<'tcx, ty::Predicate<'tcx>>,
146 index: Option<usize>, }
148
149 let mut error_map: FxIndexMap<_, Vec<_>> = self
150 .reported_trait_errors
151 .borrow()
152 .iter()
153 .map(|(&span, goals)| {
154 (span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
155 })
156 .collect();
157
158 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
163 enum ErrorSortKey {
164 SubtypeFormat(usize, usize),
165 OtherKind,
166 SizedTrait,
167 MetaSizedTrait,
168 PointeeSizedTrait,
169 Coerce,
170 WellFormed,
171 }
172 errors.sort_by_key(|e| {
173 let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() {
174 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()),
175 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => Some(pred.def_id()),
176 _ => None,
177 };
178
179 match e.obligation.predicate.kind().skip_binder() {
180 ty::PredicateKind::Subtype(_)
181 if matches!(
182 e.obligation.cause.span.desugaring_kind(),
183 Some(DesugaringKind::FormatLiteral { .. })
184 ) =>
185 {
186 let (_, row, col, ..) =
187 self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span);
188 ErrorSortKey::SubtypeFormat(row, col)
189 }
190 _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => {
191 ErrorSortKey::SizedTrait
192 }
193 _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => {
194 ErrorSortKey::MetaSizedTrait
195 }
196 _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => {
197 ErrorSortKey::PointeeSizedTrait
198 }
199 ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce,
200 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
201 ErrorSortKey::WellFormed
202 }
203 _ => ErrorSortKey::OtherKind,
204 }
205 });
206
207 for (index, error) in errors.iter().enumerate() {
208 let mut span = error.obligation.cause.span;
211 let expn_data = span.ctxt().outer_expn_data();
212 if let ExpnKind::Desugaring(_) = expn_data.kind {
213 span = expn_data.call_site;
214 }
215
216 error_map
217 .entry(span)
218 .or_default()
219 .push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
220 }
221
222 let mut is_suppressed = vec![false; errors.len()];
225 for (_, error_set) in error_map.iter() {
226 for error in error_set {
228 if let Some(index) = error.index {
229 for error2 in error_set {
233 if error2.index.is_some_and(|index2| is_suppressed[index2]) {
234 continue;
238 }
239
240 if self.error_implies(error2.goal, error.goal)
241 && !(error2.index >= error.index
242 && self.error_implies(error.goal, error2.goal))
243 {
244 info!("skipping {:?} (implied by {:?})", error, error2);
245 is_suppressed[index] = true;
246 break;
247 }
248 }
249 }
250 }
251 }
252
253 let mut reported = None;
254 for from_expansion in [false, true] {
255 for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
256 if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
257 if !error.references_error() {
258 let guar = self.report_fulfillment_error(error);
259 self.infcx.set_tainted_by_errors(guar);
260 reported = Some(guar);
261 let mut span = error.obligation.cause.span;
264 let expn_data = span.ctxt().outer_expn_data();
265 if let ExpnKind::Desugaring(_) = expn_data.kind {
266 span = expn_data.call_site;
267 }
268 self.reported_trait_errors
269 .borrow_mut()
270 .entry(span)
271 .or_insert_with(|| (vec![], guar))
272 .0
273 .push(error.obligation.as_goal());
274 }
275 if let Some(guar) = self.dcx().has_errors() {
276 self.infcx.set_tainted_by_errors(guar);
277 }
278 }
279 }
280 }
281
282 reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
286 }
287
288 #[instrument(skip(self), level = "debug")]
289 fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
290 let mut error = FulfillmentError {
291 obligation: error.obligation.clone(),
292 code: error.code.clone(),
293 root_obligation: error.root_obligation.clone(),
294 };
295 if matches!(
296 error.code,
297 FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
298 | FulfillmentErrorCode::Project(_)
299 ) && self.apply_do_not_recommend(&mut error.obligation)
300 {
301 error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
302 }
303
304 match error.code {
305 FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
306 error.obligation.clone(),
307 &error.root_obligation,
308 selection_error,
309 ),
310 FulfillmentErrorCode::Project(ref e) => {
311 self.report_projection_error(&error.obligation, e)
312 }
313 FulfillmentErrorCode::Ambiguity { overflow: None } => {
314 self.maybe_report_ambiguity(&error.obligation)
315 }
316 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
317 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
318 }
319 FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
320 .report_mismatched_types(
321 &error.obligation.cause,
322 error.obligation.param_env,
323 expected_found.expected,
324 expected_found.found,
325 *err,
326 )
327 .emit(),
328 FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
329 let mut diag = self.report_mismatched_consts(
330 &error.obligation.cause,
331 error.obligation.param_env,
332 expected_found.expected,
333 expected_found.found,
334 *err,
335 );
336 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
337 if let ObligationCauseCode::WhereClause(..)
338 | ObligationCauseCode::WhereClauseInExpr(..) = code
339 {
340 self.note_obligation_cause_code(
341 error.obligation.cause.body_id,
342 &mut diag,
343 error.obligation.predicate,
344 error.obligation.param_env,
345 code,
346 &mut vec![],
347 &mut Default::default(),
348 );
349 }
350 diag.emit()
351 }
352 FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
353 }
354 }
355
356 fn get_extern_crate_renamed_symbol(&self, trait_def_id: DefId) -> Option<Symbol> {
357 if !trait_def_id.is_local()
358 && let Some(data) = self.tcx.extern_crate(trait_def_id.krate)
359 && let rustc_session::cstore::ExternCrateSource::Extern(def_id) = data.src
360 {
361 self.tcx.opt_item_name(def_id)
362 } else {
363 None
364 }
365 }
366
367 pub fn check_same_definition_different_crate<F>(
368 &self,
369 err: &mut Diag<'_>,
370 expected_did: DefId,
371 found_dids: impl Iterator<Item = DefId>,
372 get_impls: F,
373 ty: &str,
374 ) -> bool
375 where
376 F: Fn(DefId) -> Vec<Span>,
377 {
378 let krate = self.tcx.crate_name(expected_did.krate);
379 let name = self.tcx.item_name(expected_did);
380 let locally_renamed_krate = self
381 .get_extern_crate_renamed_symbol(expected_did)
382 .map_or(None, |s| if s != krate { Some(s) } else { None });
383 let definitions_with_same_path: UnordSet<_> = found_dids
384 .filter(|def_id| {
385 def_id.krate != expected_did.krate
386 && (locally_renamed_krate == self.get_extern_crate_renamed_symbol(*def_id)
387 || self.tcx.crate_name(def_id.krate) == krate)
388 && self.tcx.item_name(def_id) == name
389 })
390 .map(|def_id| (self.tcx.def_path_str(def_id), def_id))
391 .collect();
392
393 let definitions_with_same_path =
394 definitions_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
395 let mut suggested = false;
396 let mut trait_is_impl = false;
397
398 if !definitions_with_same_path.is_empty() {
399 let mut span: MultiSpan = self.tcx.def_span(expected_did).into();
400 span.push_span_label(
401 self.tcx.def_span(expected_did),
402 format!("this is the expected {ty}"),
403 );
404 suggested = true;
405 for (_, definition_with_same_path) in &definitions_with_same_path {
406 let definitions_impls = get_impls(*definition_with_same_path);
407 if definitions_impls.is_empty() {
408 continue;
409 }
410
411 for candidate_span in definitions_impls {
412 span.push_span_label(candidate_span, format!("this is the found {ty}"));
413 trait_is_impl = true;
414 }
415 }
416 if !trait_is_impl {
417 for (_, def_id) in definitions_with_same_path {
418 span.push_span_label(
419 self.tcx.def_span(def_id),
420 format!("this is the {ty} that was imported"),
421 );
422 }
423 }
424 self.note_two_crate_versions(expected_did, span, err);
425 err.help("you can use `cargo tree` to explore your dependency tree");
426 }
427 suggested
428 }
429}
430
431pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
434 use std::fmt::Write;
435
436 let trait_ref = tcx.impl_opt_trait_ref(impl_def_id)?.instantiate_identity();
437 let mut w = "impl".to_owned();
438
439 #[derive(Debug, Default)]
440 struct SizednessFound {
441 sized: bool,
442 meta_sized: bool,
443 }
444
445 let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
446
447 let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
448
449 let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
450 if !arg_names.is_empty() {
451 w.push('<');
452 w.push_str(&arg_names.join(", "));
453 w.push('>');
454
455 for ty in args.types() {
456 types_with_sizedness_bounds.insert(ty, SizednessFound::default());
458 }
459 }
460
461 write!(
462 w,
463 " {}{} for {}",
464 tcx.impl_polarity(impl_def_id).as_str(),
465 trait_ref.print_only_trait_path(),
466 tcx.type_of(impl_def_id).instantiate_identity()
467 )
468 .unwrap();
469
470 let predicates = tcx.predicates_of(impl_def_id).predicates;
471 let mut pretty_predicates = Vec::with_capacity(predicates.len());
472
473 let sized_trait = tcx.lang_items().sized_trait();
474 let meta_sized_trait = tcx.lang_items().meta_sized_trait();
475
476 for (p, _) in predicates {
477 if let Some(trait_clause) = p.as_trait_clause() {
479 let self_ty = trait_clause.self_ty().skip_binder();
480 let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
481 if Some(trait_clause.def_id()) == sized_trait {
482 sizedness_of.sized = true;
483 continue;
484 } else if Some(trait_clause.def_id()) == meta_sized_trait {
485 sizedness_of.meta_sized = true;
486 continue;
487 }
488 }
489
490 pretty_predicates.push(p.to_string());
491 }
492
493 for (ty, sizedness) in types_with_sizedness_bounds {
494 if !tcx.features().sized_hierarchy() {
495 if sizedness.sized {
496 } else {
498 pretty_predicates.push(format!("{ty}: ?Sized"));
499 }
500 } else {
501 if sizedness.sized {
502 pretty_predicates.push(format!("{ty}: Sized"));
504 } else if sizedness.meta_sized {
505 pretty_predicates.push(format!("{ty}: MetaSized"));
506 } else {
507 pretty_predicates.push(format!("{ty}: PointeeSized"));
508 }
509 }
510 }
511
512 if !pretty_predicates.is_empty() {
513 write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
514 }
515
516 w.push(';');
517 Some(w)
518}
519
520impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
521 pub fn report_extra_impl_obligation(
522 &self,
523 error_span: Span,
524 impl_item_def_id: LocalDefId,
525 trait_item_def_id: DefId,
526 requirement: &dyn fmt::Display,
527 ) -> Diag<'a> {
528 let mut err = struct_span_code_err!(
529 self.dcx(),
530 error_span,
531 E0276,
532 "impl has stricter requirements than trait"
533 );
534
535 if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
536 if let Some(span) = self.tcx.hir_span_if_local(trait_item_def_id) {
537 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
538 err.span_label(span, format!("definition of `{item_name}` from trait"));
539 }
540 }
541
542 err.span_label(error_span, format!("impl has extra requirement {requirement}"));
543
544 err
545 }
546}
547
548pub fn report_dyn_incompatibility<'tcx>(
549 tcx: TyCtxt<'tcx>,
550 span: Span,
551 hir_id: Option<hir::HirId>,
552 trait_def_id: DefId,
553 violations: &[DynCompatibilityViolation],
554) -> Diag<'tcx> {
555 let trait_str = tcx.def_path_str(trait_def_id);
556 let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
557 hir::Node::Item(item) => match item.kind {
558 hir::ItemKind::Trait(_, _, _, ident, ..)
559 | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span),
560 _ => unreachable!(),
561 },
562 _ => None,
563 });
564
565 let mut err = struct_span_code_err!(
566 tcx.dcx(),
567 span,
568 E0038,
569 "the {} `{}` is not dyn compatible",
570 tcx.def_descr(trait_def_id),
571 trait_str
572 );
573 err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
574
575 attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
576
577 let mut reported_violations = FxIndexSet::default();
578 let mut multi_span = vec![];
579 let mut messages = vec![];
580 for violation in violations {
581 if let DynCompatibilityViolation::SizedSelf(sp) = &violation
582 && !sp.is_empty()
583 {
584 reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into()));
587 }
588 if reported_violations.insert(violation.clone()) {
589 let spans = violation.spans();
590 let msg = if trait_span.is_none() || spans.is_empty() {
591 format!("the trait is not dyn compatible because {}", violation.error_msg())
592 } else {
593 format!("...because {}", violation.error_msg())
594 };
595 if spans.is_empty() {
596 err.note(msg);
597 } else {
598 for span in spans {
599 multi_span.push(span);
600 messages.push(msg.clone());
601 }
602 }
603 }
604 }
605 let has_multi_span = !multi_span.is_empty();
606 let mut note_span = MultiSpan::from_spans(multi_span.clone());
607 if let (Some(trait_span), true) = (trait_span, has_multi_span) {
608 note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
609 }
610 for (span, msg) in iter::zip(multi_span, messages) {
611 note_span.push_span_label(span, msg);
612 }
613 err.span_note(
614 note_span,
615 "for a trait to be dyn compatible it needs to allow building a vtable\n\
616 for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
617 );
618
619 if trait_span.is_some() {
621 let mut potential_solutions: Vec<_> =
622 reported_violations.into_iter().map(|violation| violation.solution()).collect();
623 potential_solutions.sort();
624 potential_solutions.dedup();
626 for solution in potential_solutions {
627 solution.add_to(&mut err);
628 }
629 }
630
631 attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
632
633 err
634}
635
636fn attempt_dyn_to_enum_suggestion(
639 tcx: TyCtxt<'_>,
640 trait_def_id: DefId,
641 trait_str: &str,
642 err: &mut Diag<'_>,
643) {
644 let impls_of = tcx.trait_impls_of(trait_def_id);
645
646 if !impls_of.blanket_impls().is_empty() {
647 return;
648 }
649
650 let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
651 .non_blanket_impls()
652 .values()
653 .flatten()
654 .map(|impl_id| {
655 let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
658
659 match impl_type.kind() {
664 ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
665 return None;
666 }
667 _ => {}
668 }
669 Some(impl_type)
670 })
671 .collect();
672 let Some(concrete_impls) = concrete_impls else { return };
673
674 const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
675 if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
676 return;
677 }
678
679 let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
680 tcx.resolutions(()).effective_visibilities.is_exported(def_id)
684 } else {
685 false
686 };
687
688 if let [only_impl] = &concrete_impls[..] {
689 let within = if externally_visible { " within this crate" } else { "" };
690 err.help(with_no_trimmed_paths!(format!(
691 "only type `{only_impl}` implements `{trait_str}`{within}; \
692 consider using it directly instead."
693 )));
694 } else {
695 let types = concrete_impls
696 .iter()
697 .map(|t| with_no_trimmed_paths!(format!(" {}", t)))
698 .collect::<Vec<String>>()
699 .join("\n");
700
701 err.help(format!(
702 "the following types implement `{trait_str}`:\n\
703 {types}\n\
704 consider defining an enum where each variant holds one of these types,\n\
705 implementing `{trait_str}` for this new enum and using it instead",
706 ));
707 }
708
709 if externally_visible {
710 err.note(format!(
711 "`{trait_str}` may be implemented in other crates; if you want to support your users \
712 passing their own types here, you can't refer to a specific type",
713 ));
714 }
715}
716
717fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
720 let Some(hir_id) = hir_id else { return };
721 let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
722 let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
723
724 let Some((_id, first_non_type_parent_node)) =
729 tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
730 else {
731 return;
732 };
733 if first_non_type_parent_node.fn_sig().is_none() {
734 return;
735 }
736
737 err.span_suggestion_verbose(
738 ty.span.until(trait_ref.span),
739 "consider using an opaque type instead",
740 "impl ",
741 Applicability::MaybeIncorrect,
742 );
743}