# Expr/c and wrap-expr/c not error highlighting what contract states it is blaming

**URL:** <https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369>\
**Category:** Questions & Answers\
**Created:** [November 28, 2024, 10:33am UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369 "2024-11-28T10:33:40Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![sora22](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sora22/32/2622_2.png) [@sora22](https://racket.discourse.group/u/sora22)\
**Post date:** [November 28, 2024, 10:33am UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/1 "2024-11-28T10:33:40Z")

</div>

Don't know if I'm doing something incorrect or if this is just a bug. Been having a nightmare of a time trying to get expr/c and wrap-expr/c to work with the macros I've been writing. Whenever I attempt to use one of them and click the singular red octagon with a cross in it, it almost always takes me into either the internal contract.rkt or kw.rkt file. The smallest breaking example I could come up with is this:

```scheme
#lang racket
(require (for-syntax syntax/contract
                     syntax/parse))

(define-syntax (test stx) 
  (syntax-parse stx
    [(_ x)
     #:with x/c (wrap-expr/c #'integer? #'x)
     #'x/c]))

(test '(a b c))

```

Running that code on my system causes the error highlighting to occur in contract.rkt and returns this error message:

```scheme
../../../../nix/store/rgfyzwxj5s8783kb1p4cw33fdpa5lpg3-racket-8.13/share/racket/collects/syntax/contract.rkt:95:21: test: contract violation
  expected: integer?
  given: '(a b c)
  in: integer?
      macro argument contract
  contract from: 
      /home/sora/Documents/research-notes/testing-macro-contracts.rkt
  blaming: /home/sora/Documents/research-notes/testing-macro-contracts.rkt
   (assuming the contract is correct)
  at: /home/sora/Documents/research-notes/testing-macro-contracts.rkt:13:6

```

Any idea what I may be doing wrong?

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 29, 2024, 2:12pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/3 "2024-11-29T14:12:56Z")

</div>

My lazy armchair guess: You need to use [syntax/loc](https://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%2Floc%29%29) instead of `syntax` a.k.a. `#'`.

So instead of `#'x/c` a.k.a. `(syntax x/c)`: You could use `(syntax/loc x x/c)` to give the new, returned syntax the same srcloc as the original `x` piece of syntax (instead of the default srcloc inside the macro).

* * *

Although there are probably better explanations/examples, I wrote a [blog post](https://www.greghendershott.com/2014/01/syntax-loc-and-unit-tests.html) when I first learned about this. It also links to a post about the situation where you want the srcloc on a specific piece inside a `begin`.

---

<div class="post-metadata">

**Author:** ![sora22](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sora22/32/2622_2.png) [@sora22](https://racket.discourse.group/u/sora22)\
**Post date:** [November 29, 2024, 3:46pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/4 "2024-11-29T15:46:14Z")

</div>

No dice using syntax/loc, the error highlighting still appears in contract.rkt unfortunately (Thank you for your blog posts and fear of macros btw, both have been invaluable for me)

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 29, 2024, 4:31pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/5 "2024-11-29T16:31:13Z")

</div>

Ah, sorry.

So it looks like the _text_ at the end of the contract blame _message_ knows the correct location:

```scheme
  at: /home/sora/Documents/research-notes/testing-macro-contracts.rkt:13:6

```

The problem is that the runtime error location used by Dr Racket is not there -- instead it's inside the macro definition in `contract.rkt`.

* * *

When I change the end of your program from

```scheme
(test '(a b c))

```

to

```scheme
(with-handlers ([exn? (λ (e)
                        (println e)
                        (println (exn:srclocs? e)) ;; #f
                        (when (exn:fail:contract:blame? e)
                          (println (blame-source (exn:fail:contract:blame-object e)))))])
  (test '(a b c)))

```

It outputs:

```scheme
(exn:fail:contract:blame
 "test: contract violation\n expected: integer?\n given: '(a b c)\n in: integer?\n macro argument contract\n contract from: \n /home/greg/src/racket/examples/wrap-expr.rkt\n blaming: /home/greg/src/racket/examples/wrap-expr.rkt\n (assuming the contract is correct)\n at: /home/greg/src/racket/examples/wrap-expr.rkt:17:8"
 #<continuation-mark-set>
 #<blame-yes-swap>)
#f
(srcloc #<path:/home/greg/src/racket/examples/wrap-expr.rkt> 17 8 513 8)

```

What I'm (mis?)understanding from this:

The contract failure exception:

- does not supply a useful location in the continuation mark set (you get inside the macro)
- does not supply any `exn:srclos` (another possible provider of locations)
- _does_ supply a blame object, with the correct srcloc -- **however** DrRacket (apparently) and Racket Mode (definitely) don't look for this

So... I'm not sure if this is a deficiency in `wrap-expr/c` or contract blame exceptions, or, a to-do item for tools like DrR and Racket Mode (i.e. "here is yet another place to look for error locations"), or, some other issue I'm failing to understand. Maybe @robby can say more?

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 29, 2024, 4:55pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/6 "2024-11-29T16:55:22Z")

</div>

It looks like the goal is to get a better stacktrace for the error message, if I'm understanding correctly, so that would have to be something inside `wrap-expr/c` or things it calls (coupled with using errortrace which, iiuc, OP is already using), not the contract system or the IDE.

At this point I think I'll pass the @ to @ryanc 😅

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 29, 2024, 5:33pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/7 "2024-11-29T17:33:03Z")

</div>

IIUC: Having `exn:fail:contract:blame` support `prop:exn:srclocs` (and supply the same srcloc as `blame-source`) would suffice to make "go to error" to work for Racket Mode and Dr Racket.

[Otherwise, I could imagine tools adding this as another possible source of error locations. Which I'm willing to do, in Racket Mode. But that might justify adding a new doc page for tool authors, to inventory these sources. 😄]

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 29, 2024, 7:09pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/8 "2024-11-29T19:09:46Z")

</div>

> [@greghendershott](#):
>
> IIUC: Having `exn:fail:contract:blame` support `prop:exn:srclocs` (and supply the same srcloc as `blame-source`) would suffice to make "go to error" to work for Racket Mode and Dr Racket.

I tried that, and I see what you mean. The diff is straightforward, if we decide to go that way, namely:

```scheme
index 4226e31d8f..1023b2917a 100644
--- a/racket/collects/racket/contract/private/blame.rkt
+++ b/racket/collects/racket/contract/private/blame.rkt
@@ -345,6 +345,8 @@
 (define (show-blame-negative b) (show-blame blame-negative b))
 
 (define-struct (exn:fail:contract:blame exn:fail:contract) [object]
+ #:property prop:exn:srclocs
+ (λ (x) (list (blame-source (exn:fail:contract:blame-object x))))
   #:transparent)

```

The only possible problem I see is that it means that the location where the contract gets attached is going to take priority over the location where the violation is discovered. In the example here, they are the same, but with functions they'll be different and `contract-out` is going to make it always be in the importing module. For example, with this these two files:

```scheme
#lang racket
(provide
 (contract-out
  [f (-> integer? integer?)]))
(define (f x) x)

```

```scheme
#lang racket
(require "tmp.rkt")
(f #f)

```

(where the first one is named `"tmp.rkt"`) the error location is always in tmp.rkt even though the top of the stack is a very useful spot to look.

But maybe that's more of a problem with the way that DrRacket is interpreting the information it finds in the exception record?

I'm not sure what's the right thing here. What do you think?

> [@](#):
>
> [Otherwise, I could imagine tools adding this as another possible source of error locations. Which I'm willing to do, in Racket Mode. But that might justify adding a new doc page for tool authors, to inventory these sources. 😄]

Yeah, it does seem to be getting to be a lot, doesn't it! 😄 It definitely seems like we should be able to use an existing path or we should have a clearer justification for adding a new one and the various IDEs should all be updated to use it.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 29, 2024, 8:06pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/9 "2024-11-29T20:06:23Z")

</div>

I agree that in your example, the call site is the preferred, most relevant location.

Two questions in response that occur to me:

1. Today, the `at:` clause of the blame message describes a location -- but only textually. Exposing that as structured data -- as a srcloc -- seems like a reasonable thing to do.

2. Today, already, there exists the situation where an exn supplies srclocs, but of course there also exists "context" (whether from errortrace or continuation marks).

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 30, 2024, 2:02am UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/10 "2024-11-30T02:02:55Z")

</div>

I'm not sure this is written down anywhere, but I'd always though of the source location that's in a syntax error as _the_ source location to show in an IDE and the prop:exn:srclocs as an extensible way to allow other exceptions to offer such source locations, as effectively, commands to the IDE to send the focus to that spot. That's why prop:exn:srclocs supersedes the stacktrace locations, at least in drr.

I'm open to rethinking this or generalizing it somehow.

Separately from that question, there is also the question of what source location we shoudl be showing here. I feel like the source location where the contract is established is an interesting one, if someone wants to find out what the contract actually was. But it seems secondary to the spot where the error was discovered (the top of the stack). That's what led to my suggestion that we should change `wrap-expr/c` so that the top of the stack comes out right in examples like at the top of this thread.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 30, 2024, 2:37am UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/11 "2024-11-30T02:37:42Z")

</div>

> [@robby](#):
>
> I'm not sure this is written down anywhere, but I'd always though of the source location that's in a syntax error as _the_ source location to show in an IDE and the prop:exn:srclocs as an extensible way to allow other exceptions to offer such source locations, as effectively, commands to the IDE to send the focus to that spot. That's why prop:exn:srclocs supersedes the stacktrace locations, at least in drr.
> 
> I'm open to rethinking this or generalizing it somehow.

I think actually I'm OK with the status quo.

Note that things like rackunit test failures also use prop:exn:srclocs, IIRC. Not just "syntax errors" per se. The status quo has worked fine for those cases, too.

That's why I immediately jumped to the idea of exn:fail:contract:blame using prop:exn:srclocs. But if instead you can "change the top of the stack" for both errortrace and continuation marks, that also works!

> [@robby](#):
>
> Separately from that question, there is also the question of what source location we shoudl be showing here. I feel like the source location where the contract is established is an interesting one, if someone wants to find out what the contract actually was. But it seems secondary to the spot where the error was discovered (the top of the stack). That's what led to my suggestion that we should change `wrap-expr/c` so that the top of the stack comes out right in examples like at the top of this thread.

Yep, the part where I suggested, oh just use the blame object location, was simplistic.

That would only work if someone does the work to change the blame object location to the desired, user-apparent top of the stack.

And maybe also change the "at:" location _text_, so they all agree?

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 30, 2024, 12:29pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/12 "2024-11-30T12:29:22Z")

</div>

> [@greghendershott](#):
>
> Note that things like rackunit test failures also use prop:exn:srclocs, IIRC. Not just "syntax errors" per se. The status quo has worked fine for those cases, too.

Ah, right! And that one also fits the "please show this location" as people probably want to see the precise test case that fails when one does. So this seems to be working.

> [@greghendershott](#):
>
> That would only work if someone does the work to change the blame object location to the desired, user-apparent top of the stack.
> 
> And maybe also change the "at:" location _text_, so they all agree?

I'm not following this part, in particular I'm not sure how we're going to get the top of the stack to put into the record.

I could also change the word "at" to be something more suggestive like "contract established at" or something?

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 30, 2024, 2:11pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/13 "2024-11-30T14:11:05Z")

</div>

I think the top example here cued me to misremember what the blame object a.k.a. "at:" location is supposed to be (and even though you'd explained it above). Sorry!

IIUC now, it's _not_ meant to be the location blamed for the violation. So N/A for "the most important error location to show".

Instead it's extra info about about the contract itself.

> [@robby](#):
>
> I could also change the word "at" to be something more suggestive like "contract established at" or something?

Error messages are hard, but yes, I think that would help.

* * *

So I guess the TL;DR is -- of course -- to do your original idea:

> [@robby](#):
>
> we should change `wrap-expr/c` so that the top of the stack comes out right in examples like at the top of this thread.

---

<div class="post-metadata">

**Author:** ![sora22](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sora22/32/2622_2.png) [@sora22](https://racket.discourse.group/u/sora22)\
**Post date:** [December 1, 2024, 7:13pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/14 "2024-12-01T19:13:01Z")

</div>

In case anyone else is dealing with a similar problem and is looking for a workaround, catching and re-raising a new exception type that supports `prop:exn:srclocs` using the srcloc of the blame like greg mentioned at least appears to fix most of my problems:

```scheme
#lang racket
(require (for-syntax syntax/contract
                     syntax/parse))

(define a-custom-contract
  (listof (listof (or/c 'z 'y 'x))))

(define-struct (exn:fail:contract:blame0 exn:fail:contract) [object]
  #:property prop:exn:srclocs
  (lambda (x) (list (blame-source (exn:fail:contract:blame0-object x))))
  #:transparent)

(define-syntax (test stx) 
  (syntax-parse stx
    [(_ x)
     #:with x/c (wrap-expr/c #'a-custom-contract #'x)
     #'(with-handlers ([exn:fail:contract:blame?
                        (lambda (e) (raise (exn:fail:contract:blame0 (exn-message e)
                                                                     (current-continuation-marks)
                                                                     (exn:fail:contract:blame-object e))))])
         x/c)]))

(test '(a b c))

```

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [December 2, 2024, 7:29pm UTC](https://racket.discourse.group/t/expr-c-and-wrap-expr-c-not-error-highlighting-what-contract-states-it-is-blaming/3369/15 "2024-12-02T19:29:43Z")

</div>

Hi @sora22 : I'm glad you found something that works for you! One caution: if you're using contracts for functions, this may not give the best results. If you don't know if the contract is going to be like that or not, then you can test at runtime and either swap the exception or not, depending on if the contract answers true to [`flat-contract?`](https://docs.racket-lang.org/reference/contract-utilities.html#%28def._%28%28lib._racket%2Fcontract%2Fprivate%2Fguts..rkt%29._flat-contract~3f%29%29).
